diff --git a/.clang-tidy b/.clang-tidy index 808185c..eae1f9f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -19,6 +19,7 @@ Checks: >- -bugprone-easily-swappable-parameters, -llvm-header-guard, -cert-dcl03-c, + -boost-use-ranges, -hicpp-static-assert, -misc-static-assert, -modernize-macro-to-enum, diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fe4c30c..ab97081 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,12 +1,12 @@ name: Main Workflow on: [ push, pull_request ] env: - LLVM_VERSION: 15 + LLVM_VERSION: 19 jobs: debug: if: github.event_name == 'push' runs-on: ubuntu-latest - container: ghcr.io/opencyphal/toolshed:ts22.4.10 + container: ghcr.io/opencyphal/toolshed:ts24.4.3 strategy: matrix: toolchain: [ 'clang', 'gcc' ] @@ -46,7 +46,7 @@ jobs: optimizations: if: github.event_name == 'push' runs-on: ubuntu-latest - container: ghcr.io/opencyphal/toolshed:ts22.4.10 + container: ghcr.io/opencyphal/toolshed:ts24.4.3 strategy: matrix: toolchain: [ 'clang', 'gcc' ] @@ -123,7 +123,7 @@ jobs: sonar: runs-on: ubuntu-latest - container: ghcr.io/opencyphal/toolshed:ts22.4.10 + container: ghcr.io/opencyphal/toolshed:ts24.4.3 if: > ( (github.event_name == 'pull_request' || contains(github.ref, '/main') || contains(github.ref, '/release')) && @@ -176,7 +176,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: DoozyX/clang-format-lint-action@v0.17 + - uses: DoozyX/clang-format-lint-action@v0.20 with: source: './libudpard ./tests' extensions: 'c,h,cpp,hpp' diff --git a/MIGRATION_v1.x_to_v2.0.md b/MIGRATION_v1.x_to_v2.0.md new file mode 100644 index 0000000..4771b45 --- /dev/null +++ b/MIGRATION_v1.x_to_v2.0.md @@ -0,0 +1,197 @@ +# Migration Guide: Upgrading from LibUDPard v1.x to v2.0 + +This migration guide provides step-by-step instructions to help you update your application code from LibUDPard version 1.x to version 2.0. The guide highlights the key changes in the API and offers recommendations on how to adapt your code accordingly. + +## Introduction + +LibUDPard version 2.0 introduces several significant changes to improve memory management and payload handling. This guide will help you understand these changes and update your application code to be compatible with the new version. + +These changes do not affect wire compatibility. + +## Version Changes + +- **LibUDPard Version**: + - **Old**: `UDPARD_VERSION_MAJOR 1`, `UDPARD_VERSION_MINOR 2` + - **New**: `UDPARD_VERSION_MAJOR 2`, `UDPARD_VERSION_MINOR 0` +- **Cyphal Specification Version**: Remains the same (`1.0`). + +## Key API Changes + +### UdpardTx Structure Changes + +- **Memory Resource Field**: The `UdpardTx` structure's `memory` field type has changed from `UdpardMemoryResource` to `UdpardTxMemoryResources`. + + ```c + // In v1.x + struct UdpardTx { + // ... + struct UdpardMemoryResource memory; + // ... + }; + + // In v2.0 + struct UdpardTx { + // ... + struct UdpardTxMemoryResources memory; + // ... + }; + ``` + +### Memory Management Adjustments + +- **Separate Memory Resources**: `UdpardTxMemoryResources` now allows separate memory resources for fragment handles and payload storage. + + ```c + struct UdpardTxMemoryResources { + struct UdpardMemoryResource fragment; // For UdpardTxItem allocations + struct UdpardMemoryResource payload; // For datagram payload allocations + }; + ``` + +- **Memory Allocation Changes**: The number of memory allocations per datagram has increased from one to two: + - **v1.x**: One allocation per datagram (including `UdpardTxItem` and payload). + - **v2.0**: Two allocations per datagram—one for `UdpardTxItem` and one for the payload. + +### UdpardTxItem Structure Updates + +- **Mutable datagram_payload Field**: The `datagram_payload` field in `UdpardTxItem` is now mutable, allowing ownership transfer of the payload. + +- **New priority Field**: A new `priority` field has been added to `UdpardTxItem` to retain the original transfer priority level. + + ```c + struct UdpardTxItem { + // ... + enum UdpardPriority priority; // New field in v2.0 + struct UdpardMutablePayload datagram_payload; // Now mutable + // ... + }; + ``` + +### Function Signature Modifications + +- **udpardTxInit**: The `memory` parameter type has changed to `UdpardTxMemoryResources`. + + ```c + // In v1.x + int_fast8_t udpardTxInit( + struct UdpardTx* self, + const UdpardNodeID* local_node_id, + size_t queue_capacity, + struct UdpardMemoryResource memory + ); + + // In v2.0 + int_fast8_t udpardTxInit( + struct UdpardTx* self, + const UdpardNodeID* local_node_id, + size_t queue_capacity, + struct UdpardTxMemoryResources memory + ); + ``` + +- **udpardTxFree**: The `memory` parameter type has changed to `UdpardTxMemoryResources`. + + ```c + // In v1.x + void udpardTxFree( + const struct UdpardMemoryResource memory, + struct UdpardTxItem* item + ); + + // In v2.0 + void udpardTxFree( + const struct UdpardTxMemoryResources memory, + struct UdpardTxItem* item + ); + ``` + +- **udpardTxPeek**: The return type has changed from `const struct UdpardTxItem*` to `struct UdpardTxItem*` to allow modification of the `datagram_payload` field. + + ```c + // In v1.x + const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* self); + + // In v2.0 + struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* self); + ``` + +## Migration Steps + +Follow these steps to update your application code to be compatible with LibUDPard v2.0. + +### 1. Update UdpardTx Initialization + +- **Adjust the `udpardTxInit` Call**: Update the `memory` parameter to use `UdpardTxMemoryResources`. + + ```c + // Before (v1.x) + struct UdpardMemoryResource tx_memory = { /*...*/ }; + udpardTxInit(&tx_instance, &local_node_id, queue_capacity, tx_memory); + + // After (v2.0) + struct UdpardTxMemoryResources tx_memory = { + .fragment = { /*...*/ }, + .payload = { /*...*/ } + }; + udpardTxInit(&tx_instance, &local_node_id, queue_capacity, tx_memory); + ``` + +- **Define Separate Memory Resources**: Initialize separate memory resources for fragments and payloads. + +### 2. Adjust Memory Resources + +- **Update Memory Allocation Logic**: Ensure that your memory allocator handles two separate allocations per datagram—one for `UdpardTxItem` and one for the payload. + + ```c + // Example allocator adjustments + void* allocate_fragment(void* user_reference, size_t size) { /*...*/ } + void* allocate_payload(void* user_reference, size_t size) { /*...*/ } + ``` + +### 3. Modify UdpardTxItem Usage + +- **Handle Mutable Payloads**: Since `datagram_payload` is now mutable, you can transfer ownership of the payload to another component (e.g., transmission media) by nullifying the `size` and `data` fields after copying. + + ```c + struct UdpardTxItem* tx_item = udpardTxPeek(&tx_instance); + if (tx_item) { + // Transfer ownership of the payload + transmit_payload(tx_item->datagram_payload.data, tx_item->datagram_payload.size); + tx_item->datagram_payload.data = NULL; + tx_item->datagram_payload.size = 0; + + // Pop and free the item after transmission + udpardTxPop(&tx_instance, tx_item); + udpardTxFree(tx_instance.memory, tx_item); + } + ``` + +- **Utilize the New priority Field**: Access the `priority` field in `UdpardTxItem` if needed for your application logic. + + ```c + enum UdpardPriority tx_priority = tx_item->priority; + ``` + +### 4. Revise Function Calls + +- **Update `udpardTxFree` Calls**: Pass the updated `memory` parameter type. + + ```c + // Before (v1.x) + udpardTxFree(tx_memory, tx_item); + + // After (v2.0) + udpardTxFree(tx_instance.memory, tx_item); + ``` + +- **Modify `udpardTxPeek` Usage**: Since `udpardTxPeek` now returns a mutable pointer, update your code to handle the mutable `UdpardTxItem`. + + ```c + // Before (v1.x) + const struct UdpardTxItem* tx_item = udpardTxPeek(&tx_instance); + + // After (v2.0) + struct UdpardTxItem* tx_item = udpardTxPeek(&tx_instance); + ``` + +- **Ensure Correct Deallocation**: When freeing payloads, use the appropriate memory resource from `UdpardTxMemoryResources`. diff --git a/README.md b/README.md index 6892fa4..5a5197b 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,11 @@ For complete usage examples, please refer to // --------------------------------------------- BUILD CONFIGURATION --------------------------------------------- @@ -67,51 +68,51 @@ typedef struct #define SUBJECT_MULTICAST_GROUP_ADDRESS_MASK 0xEF000000UL #define SERVICE_MULTICAST_GROUP_ADDRESS_MASK 0xEF010000UL -static inline uint32_t makeSubjectIPGroupAddress(const UdpardPortID subject_id) +static uint32_t makeSubjectIPGroupAddress(const UdpardPortID subject_id) { return SUBJECT_MULTICAST_GROUP_ADDRESS_MASK | ((uint32_t) subject_id); } -static inline uint32_t makeServiceIPGroupAddress(const UdpardNodeID destination_node_id) +static uint32_t makeServiceIPGroupAddress(const UdpardNodeID destination_node_id) { return SERVICE_MULTICAST_GROUP_ADDRESS_MASK | ((uint32_t) destination_node_id); } -static inline struct UdpardUDPIPEndpoint makeSubjectUDPIPEndpoint(const UdpardPortID subject_id) +static struct UdpardUDPIPEndpoint makeSubjectUDPIPEndpoint(const UdpardPortID subject_id) { - return (struct UdpardUDPIPEndpoint){.ip_address = makeSubjectIPGroupAddress(subject_id), // - .udp_port = UDP_PORT}; + return (struct UdpardUDPIPEndpoint) {.ip_address = makeSubjectIPGroupAddress(subject_id), // + .udp_port = UDP_PORT}; } -static inline struct UdpardUDPIPEndpoint makeServiceUDPIPEndpoint(const UdpardNodeID destination_node_id) +static struct UdpardUDPIPEndpoint makeServiceUDPIPEndpoint(const UdpardNodeID destination_node_id) { - return (struct UdpardUDPIPEndpoint){.ip_address = makeServiceIPGroupAddress(destination_node_id), - .udp_port = UDP_PORT}; + return (struct UdpardUDPIPEndpoint) {.ip_address = makeServiceIPGroupAddress(destination_node_id), + .udp_port = UDP_PORT}; } /// Used for inserting new items into AVL trees. Refer to the documentation for cavlSearch() for details. -static inline struct UdpardTreeNode* avlTrivialFactory(void* const user_reference) +static struct UdpardTreeNode* avlTrivialFactory(void* const user_reference) { return (struct UdpardTreeNode*) user_reference; } -static inline size_t smaller(const size_t a, const size_t b) +static size_t smaller(const size_t a, const size_t b) { return (a < b) ? a : b; } -static inline size_t larger(const size_t a, const size_t b) +static size_t larger(const size_t a, const size_t b) { return (a > b) ? a : b; } -static inline uint32_t max32(const uint32_t a, const uint32_t b) +static uint32_t max32(const uint32_t a, const uint32_t b) { return (a > b) ? a : b; } /// Returns the sign of the subtraction of the operands; zero if equal. This is useful for AVL search. -static inline int_fast8_t compare32(const uint32_t a, const uint32_t b) +static int_fast8_t compare32(const uint32_t a, const uint32_t b) { int_fast8_t result = 0; if (a > b) @@ -125,19 +126,19 @@ static inline int_fast8_t compare32(const uint32_t a, const uint32_t b) return result; } -static inline void* memAlloc(const struct UdpardMemoryResource memory, const size_t size) +static void* memAlloc(const struct UdpardMemoryResource memory, const size_t size) { UDPARD_ASSERT(memory.allocate != NULL); return memory.allocate(memory.user_reference, size); } -static inline void memFree(const struct UdpardMemoryResource memory, const size_t size, void* const data) +static void memFree(const struct UdpardMemoryResource memory, const size_t size, void* const data) { UDPARD_ASSERT(memory.deallocate != NULL); memory.deallocate(memory.user_reference, size, data); } -static inline void memFreePayload(const struct UdpardMemoryDeleter memory, const struct UdpardMutablePayload payload) +static void memFreePayload(const struct UdpardMemoryDeleter memory, const struct UdpardMutablePayload payload) { UDPARD_ASSERT(memory.deallocate != NULL); if (payload.data != NULL) @@ -146,7 +147,7 @@ static inline void memFreePayload(const struct UdpardMemoryDeleter memory, const } } -static inline void memZero(const size_t size, void* const data) +static void memZero(const size_t size, void* const data) { // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) (void) memset(data, 0, size); @@ -158,7 +159,7 @@ static inline void memZero(const size_t size, void* const data) #define HEADER_CRC_RESIDUE 0x0000U #define HEADER_CRC_SIZE_BYTES 2U -static inline uint16_t headerCRCAddByte(const uint16_t crc, const byte_t byte) +static uint16_t headerCRCAddByte(const uint16_t crc, const byte_t byte) { static const uint16_t Table[256] = { 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, @@ -188,7 +189,7 @@ static inline uint16_t headerCRCAddByte(const uint16_t crc, const byte_t byte) Table[(uint16_t) ((uint16_t) (crc >> ByteWidth) ^ byte) & ByteMask]); } -static inline uint16_t headerCRCCompute(const size_t size, const void* const data) +static uint16_t headerCRCCompute(const size_t size, const void* const data) { UDPARD_ASSERT((data != NULL) || (size == 0U)); uint16_t out = HEADER_CRC_INITIAL; @@ -209,7 +210,7 @@ static inline uint16_t headerCRCCompute(const size_t size, const void* const dat #define TRANSFER_CRC_RESIDUE_AFTER_OUTPUT_XOR (TRANSFER_CRC_RESIDUE_BEFORE_OUTPUT_XOR ^ TRANSFER_CRC_OUTPUT_XOR) #define TRANSFER_CRC_SIZE_BYTES 4U -static inline uint32_t transferCRCAddByte(const uint32_t crc, const byte_t byte) +static uint32_t transferCRCAddByte(const uint32_t crc, const byte_t byte) { static const uint32_t Table[256] = { 0x00000000UL, 0xF26B8303UL, 0xE13B70F7UL, 0x1350F3F4UL, 0xC79A971FUL, 0x35F1141CUL, 0x26A1E7E8UL, 0xD4CA64EBUL, @@ -249,7 +250,7 @@ static inline uint32_t transferCRCAddByte(const uint32_t crc, const byte_t byte) } /// Do not forget to apply the output XOR when done, or use transferCRCCompute(). -static inline uint32_t transferCRCAdd(const uint32_t crc, const size_t size, const void* const data) +static uint32_t transferCRCAdd(const uint32_t crc, const size_t size, const void* const data) { UDPARD_ASSERT((data != NULL) || (size == 0U)); uint32_t out = crc; @@ -262,7 +263,7 @@ static inline uint32_t transferCRCAdd(const uint32_t crc, const size_t size, con return out; } -static inline uint32_t transferCRCCompute(const size_t size, const void* const data) +static uint32_t transferCRCCompute(const size_t size, const void* const data) { return transferCRCAdd(TRANSFER_CRC_INITIAL, size, data) ^ TRANSFER_CRC_OUTPUT_XOR; } @@ -271,72 +272,73 @@ static inline uint32_t transferCRCCompute(const size_t size, const void* const d // ================================================= TX PIPELINE ================================================= // ===================================================================================================================== -/// This is a subclass of UdpardTxItem. A pointer to this type can be cast to UdpardTxItem safely. -/// This is compliant with the C99 standard; paragraph 6.7.2.1.15 says: -/// A pointer to a structure object, suitably converted, points to its initial member (or if that member is a -/// bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a -/// structure object, but not at its beginning. -typedef struct -{ - struct UdpardTxItem base; - enum UdpardPriority priority; ///< Do we need this exposed in the public structure? We already have DSCP there. - // The MISRA violation here is hard to get rid of without having to allocate a separate memory block for the - // payload, which is much more costly risk-wise. - byte_t payload_buffer[]; // NOSONAR MISRA C 18.7 Flexible array member. -} TxItem; - /// Chain of TX frames prepared for insertion into a TX queue. typedef struct { - TxItem* head; - TxItem* tail; - size_t count; + struct UdpardTxItem* head; + struct UdpardTxItem* tail; + size_t count; } TxChain; -static inline TxItem* txNewItem(const struct UdpardMemoryResource memory, - const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], - const UdpardMicrosecond deadline_usec, - const enum UdpardPriority priority, - const struct UdpardUDPIPEndpoint endpoint, - const size_t datagram_payload_size, - void* const user_transfer_reference) +static bool txValidateMemoryResources(const struct UdpardTxMemoryResources memory) +{ + return (memory.fragment.allocate != NULL) && (memory.fragment.deallocate != NULL) && + (memory.payload.allocate != NULL) && (memory.payload.deallocate != NULL); +} + +static struct UdpardTxItem* txNewItem(const struct UdpardTxMemoryResources memory, + const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], + const UdpardMicrosecond deadline_usec, + const enum UdpardPriority priority, + const struct UdpardUDPIPEndpoint endpoint, + const size_t datagram_payload_size, + void* const user_transfer_reference) { - TxItem* const out = (TxItem*) memAlloc(memory, sizeof(TxItem) + datagram_payload_size); + struct UdpardTxItem* out = memAlloc(memory.fragment, sizeof(struct UdpardTxItem)); if (out != NULL) { // No tree linkage by default. - out->base.base.up = NULL; - out->base.base.lr[0] = NULL; - out->base.base.lr[1] = NULL; - out->base.base.bf = 0; + out->base.up = NULL; + out->base.lr[0] = NULL; + out->base.lr[1] = NULL; + out->base.bf = 0; // Init metadata. - out->priority = priority; - out->base.next_in_transfer = NULL; // Last by default. - out->base.deadline_usec = deadline_usec; + out->priority = priority; + out->next_in_transfer = NULL; // Last by default. + out->deadline_usec = deadline_usec; UDPARD_ASSERT(priority <= UDPARD_PRIORITY_MAX); - out->base.dscp = dscp_value_per_priority[priority]; - out->base.destination = endpoint; - out->base.user_transfer_reference = user_transfer_reference; - // The payload points to the buffer already allocated. - out->base.datagram_payload.size = datagram_payload_size; - out->base.datagram_payload.data = &out->payload_buffer[0]; + out->dscp = dscp_value_per_priority[priority]; + out->destination = endpoint; + out->user_transfer_reference = user_transfer_reference; + + void* const payload_data = memAlloc(memory.payload, datagram_payload_size); + if (NULL != payload_data) + { + out->datagram_payload.data = payload_data; + out->datagram_payload.size = datagram_payload_size; + } + else + { + memFree(memory.fragment, sizeof(struct UdpardTxItem), out); + out = NULL; + } } return out; } /// Frames with identical weight are processed in the FIFO order. /// Frames with higher weight compare smaller (i.e., put on the left side of the tree). -static inline int_fast8_t txAVLPredicate(void* const user_reference, // NOSONAR Cavl API requires pointer to non-const. - const struct UdpardTreeNode* const node) +static int_fast8_t txAVLPredicate(void* const user_reference, // NOSONAR Cavl API requires pointer to non-const. + const struct UdpardTreeNode* const node) { - const TxItem* const target = (const TxItem*) user_reference; - const TxItem* const other = (const TxItem*) (const void*) node; + const struct UdpardTxItem* const target = (const struct UdpardTxItem*) user_reference; + const struct UdpardTxItem* const other = (const struct UdpardTxItem*) (const void*) node; UDPARD_ASSERT((target != NULL) && (other != NULL)); return (target->priority >= other->priority) ? +1 : -1; } /// The primitive serialization functions are endian-agnostic. -static inline byte_t* txSerializeU16(byte_t* const destination_buffer, const uint16_t value) +static byte_t* txSerializeU16(byte_t* const destination_buffer, const uint16_t value) { byte_t* ptr = destination_buffer; *ptr++ = (byte_t) (value & ByteMask); @@ -344,7 +346,7 @@ static inline byte_t* txSerializeU16(byte_t* const destination_buffer, const uin return ptr; } -static inline byte_t* txSerializeU32(byte_t* const destination_buffer, const uint32_t value) +static byte_t* txSerializeU32(byte_t* const destination_buffer, const uint32_t value) { byte_t* ptr = destination_buffer; for (size_t i = 0; i < sizeof(value); i++) // We sincerely hope that the compiler will use memcpy. @@ -354,7 +356,7 @@ static inline byte_t* txSerializeU32(byte_t* const destination_buffer, const uin return ptr; } -static inline byte_t* txSerializeU64(byte_t* const destination_buffer, const uint64_t value) +static byte_t* txSerializeU64(byte_t* const destination_buffer, const uint64_t value) { byte_t* ptr = destination_buffer; for (size_t i = 0; i < sizeof(value); i++) // We sincerely hope that the compiler will use memcpy. @@ -364,10 +366,10 @@ static inline byte_t* txSerializeU64(byte_t* const destination_buffer, const uin return ptr; } -static inline byte_t* txSerializeHeader(byte_t* const destination_buffer, - const TransferMetadata meta, - const uint32_t frame_index, - const bool end_of_transfer) +static byte_t* txSerializeHeader(byte_t* const destination_buffer, + const TransferMetadata meta, + const uint32_t frame_index, + const bool end_of_transfer) { byte_t* ptr = destination_buffer; *ptr++ = HEADER_VERSION; @@ -390,14 +392,14 @@ static inline byte_t* txSerializeHeader(byte_t* const destination_buffe /// Produces a chain of Tx queue items for later insertion into the Tx queue. The tail is NULL if OOM. /// The caller is responsible for freeing the memory allocated for the chain. -static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, - const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], - const size_t mtu, - const UdpardMicrosecond deadline_usec, - const TransferMetadata meta, - const struct UdpardUDPIPEndpoint endpoint, - const struct UdpardPayload payload, - void* const user_transfer_reference) +static TxChain txMakeChain(const struct UdpardTxMemoryResources memory, + const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], + const size_t mtu, + const UdpardMicrosecond deadline_usec, + const TransferMetadata meta, + const struct UdpardUDPIPEndpoint endpoint, + const struct UdpardPayload payload, + void* const user_transfer_reference) { UDPARD_ASSERT(mtu > 0); UDPARD_ASSERT((payload.data != NULL) || (payload.size == 0U)); @@ -408,13 +410,13 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, size_t offset = 0U; while (offset < payload_size_with_crc) { - TxItem* const item = txNewItem(memory, - dscp_value_per_priority, - deadline_usec, - meta.priority, - endpoint, - smaller(payload_size_with_crc - offset, mtu) + HEADER_SIZE_BYTES, - user_transfer_reference); + struct UdpardTxItem* const item = txNewItem(memory, + dscp_value_per_priority, + deadline_usec, + meta.priority, + endpoint, + smaller(payload_size_with_crc - offset, mtu) + HEADER_SIZE_BYTES, + user_transfer_reference); if (NULL == out.head) { out.head = item; @@ -423,15 +425,16 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, { // C std, 6.7.2.1.15: A pointer to a structure object <...> points to its initial member, and vice versa. // Can't just read tqi->base because tqi may be NULL; https://github.com/OpenCyphal/libcanard/issues/203. - out.tail->base.next_in_transfer = (struct UdpardTxItem*) item; + out.tail->next_in_transfer = item; } out.tail = item; if (NULL == out.tail) { break; } - const bool last = (payload_size_with_crc - offset) <= mtu; - byte_t* write_ptr = txSerializeHeader(&item->payload_buffer[0], meta, (uint32_t) out.count, last); + const bool last = (payload_size_with_crc - offset) <= mtu; + byte_t* const dst_buffer = item->datagram_payload.data; + byte_t* write_ptr = txSerializeHeader(dst_buffer, meta, (uint32_t) out.count, last); if (offset < payload.size) { const size_t progress = smaller(payload.size - offset, mtu); @@ -446,7 +449,7 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, { const size_t crc_offset = offset - payload.size; UDPARD_ASSERT(crc_offset < TRANSFER_CRC_SIZE_BYTES); - const size_t available = item->base.datagram_payload.size - (size_t) (write_ptr - &item->payload_buffer[0]); + const size_t available = item->datagram_payload.size - (size_t) (write_ptr - dst_buffer); UDPARD_ASSERT(available <= TRANSFER_CRC_SIZE_BYTES); const size_t write_size = smaller(TRANSFER_CRC_SIZE_BYTES - crc_offset, available); // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) @@ -460,12 +463,12 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, return out; } -static inline int32_t txPush(struct UdpardTx* const tx, - const UdpardMicrosecond deadline_usec, - const TransferMetadata meta, - const struct UdpardUDPIPEndpoint endpoint, - const struct UdpardPayload payload, - void* const user_transfer_reference) +static int32_t txPush(struct UdpardTx* const tx, + const UdpardMicrosecond deadline_usec, + const TransferMetadata meta, + const struct UdpardUDPIPEndpoint endpoint, + const struct UdpardPayload payload, + void* const user_transfer_reference) { UDPARD_ASSERT(tx != NULL); int32_t out = 0; // The number of frames enqueued or negated error. @@ -495,7 +498,7 @@ static inline int32_t txPush(struct UdpardTx* const tx, if (chain.tail != NULL) { UDPARD_ASSERT(frame_count == chain.count); - struct UdpardTxItem* next = &chain.head->base; + struct UdpardTxItem* next = chain.head; do { const struct UdpardTreeNode* const res = @@ -513,11 +516,11 @@ static inline int32_t txPush(struct UdpardTx* const tx, else // The queue is large enough but we ran out of heap memory, so we have to unwind the chain. { out = -UDPARD_ERROR_MEMORY; - struct UdpardTxItem* head = &chain.head->base; + struct UdpardTxItem* head = chain.head; while (head != NULL) { struct UdpardTxItem* const next = head->next_in_transfer; - memFree(tx->memory, sizeof(TxItem) + head->datagram_payload.size, head); + udpardTxFree(tx->memory, head); head = next; } } @@ -526,13 +529,13 @@ static inline int32_t txPush(struct UdpardTx* const tx, return out; } -int_fast8_t udpardTxInit(struct UdpardTx* const self, - const UdpardNodeID* const local_node_id, - const size_t queue_capacity, - const struct UdpardMemoryResource memory) +int_fast8_t udpardTxInit(struct UdpardTx* const self, + const UdpardNodeID* const local_node_id, + const size_t queue_capacity, + const struct UdpardTxMemoryResources memory) { int_fast8_t ret = -UDPARD_ERROR_ARGUMENT; - if ((NULL != self) && (NULL != local_node_id) && (memory.allocate != NULL) && (memory.deallocate != NULL)) + if ((NULL != self) && (NULL != local_node_id) && txValidateMemoryResources(memory)) { ret = 0; memZero(sizeof(*self), self); @@ -562,7 +565,7 @@ int32_t udpardTxPublish(struct UdpardTx* const self, { out = txPush(self, deadline_usec, - (TransferMetadata){ + (TransferMetadata) { .priority = priority, .src_node_id = *self->local_node_id, .dst_node_id = UDPARD_NODE_ID_UNSET, @@ -593,7 +596,7 @@ int32_t udpardTxRequest(struct UdpardTx* const self, { out = txPush(self, deadline_usec, - (TransferMetadata){ + (TransferMetadata) { .priority = priority, .src_node_id = *self->local_node_id, .dst_node_id = server_node_id, @@ -625,7 +628,7 @@ int32_t udpardTxRespond(struct UdpardTx* const self, { out = txPush(self, deadline_usec, - (TransferMetadata){ + (TransferMetadata) { .priority = priority, .src_node_id = *self->local_node_id, .dst_node_id = client_node_id, @@ -639,27 +642,22 @@ int32_t udpardTxRespond(struct UdpardTx* const self, return out; } -const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self) +struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self) { - const struct UdpardTxItem* out = NULL; + struct UdpardTxItem* out = NULL; if (self != NULL) { // Paragraph 6.7.2.1.15 of the C standard says: // A pointer to a structure object, suitably converted, points to its initial member, and vice versa. - out = (const struct UdpardTxItem*) (void*) cavlFindExtremum(self->root, false); + out = (struct UdpardTxItem*) (void*) cavlFindExtremum(self->root, false); } return out; } -struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, const struct UdpardTxItem* const item) +struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, struct UdpardTxItem* const item) { - struct UdpardTxItem* out = NULL; if ((self != NULL) && (item != NULL)) { - // Intentional violation of MISRA: casting away const qualifier. This is considered safe because the API - // contract dictates that the pointer shall point to a mutable entity in RAM previously allocated by the - // memory manager. It is difficult to avoid this cast in this context. - out = (struct UdpardTxItem*) item; // NOSONAR casting away const qualifier. // Paragraph 6.7.2.1.15 of the C standard says: // A pointer to a structure object, suitably converted, points to its initial member, and vice versa. // Note that the highest-priority frame is always a leaf node in the AVL tree, which means that it is very @@ -668,14 +666,19 @@ struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, const struct Udpar UDPARD_ASSERT(self->queue_size > 0U); self->queue_size--; } - return out; + return item; } -void udpardTxFree(const struct UdpardMemoryResource memory, struct UdpardTxItem* const item) +void udpardTxFree(const struct UdpardTxMemoryResources memory, struct UdpardTxItem* const item) { if (item != NULL) { - memFree(memory, sizeof(TxItem) + item->datagram_payload.size, item); + if (item->datagram_payload.data != NULL) + { + memFree(memory.payload, item->datagram_payload.size, item->datagram_payload.data); + } + + memFree(memory.fragment, sizeof(struct UdpardTxItem), item); } } @@ -700,7 +703,7 @@ typedef struct } RxFrame; /// The primitive deserialization functions are endian-agnostic. -static inline const byte_t* txDeserializeU16(const byte_t* const source_buffer, uint16_t* const out_value) +static const byte_t* txDeserializeU16(const byte_t* const source_buffer, uint16_t* const out_value) { UDPARD_ASSERT((source_buffer != NULL) && (out_value != NULL)); const byte_t* ptr = source_buffer; @@ -711,7 +714,7 @@ static inline const byte_t* txDeserializeU16(const byte_t* const source_buffer, return ptr; } -static inline const byte_t* txDeserializeU32(const byte_t* const source_buffer, uint32_t* const out_value) +static const byte_t* txDeserializeU32(const byte_t* const source_buffer, uint32_t* const out_value) { UDPARD_ASSERT((source_buffer != NULL) && (out_value != NULL)); const byte_t* ptr = source_buffer; @@ -724,7 +727,7 @@ static inline const byte_t* txDeserializeU32(const byte_t* const source_buffer, return ptr; } -static inline const byte_t* txDeserializeU64(const byte_t* const source_buffer, uint64_t* const out_value) +static const byte_t* txDeserializeU64(const byte_t* const source_buffer, uint64_t* const out_value) { UDPARD_ASSERT((source_buffer != NULL) && (out_value != NULL)); const byte_t* ptr = source_buffer; @@ -738,7 +741,7 @@ static inline const byte_t* txDeserializeU64(const byte_t* const source_buffer, } /// This is roughly the inverse of the txSerializeHeader function, but it also handles the frame payload. -static inline bool rxParseFrame(const struct UdpardMutablePayload datagram_payload, RxFrame* const out) +static bool rxParseFrame(const struct UdpardMutablePayload datagram_payload, RxFrame* const out) { UDPARD_ASSERT((out != NULL) && (datagram_payload.data != NULL)); out->base.origin = datagram_payload; @@ -787,7 +790,7 @@ static inline bool rxParseFrame(const struct UdpardMutablePayload datagram_paylo return ok; } -static inline bool rxValidateMemoryResources(const struct UdpardRxMemoryResources memory) +static bool rxValidateMemoryResources(const struct UdpardRxMemoryResources memory) { return (memory.session.allocate != NULL) && (memory.session.deallocate != NULL) && (memory.fragment.allocate != NULL) && (memory.fragment.deallocate != NULL) && @@ -891,7 +894,7 @@ struct UdpardInternalRxSession /// This is meant to be invoked on the root of the tree. /// The maximum recursion depth is ceil(1.44*log2(FRAME_INDEX_MAX+1)-0.328) = 45 levels. // NOLINTNEXTLINE(misc-no-recursion) MISRA C:2012 rule 17.2 -static inline void rxFragmentDestroyTree(RxFragment* const self, const RxMemory memory) +static void rxFragmentDestroyTree(RxFragment* const self, const RxMemory memory) { UDPARD_ASSERT(self != NULL); memFreePayload(memory.payload, self->base.origin); @@ -911,7 +914,7 @@ static inline void rxFragmentDestroyTree(RxFragment* const self, const RxMemory /// This is meant to be invoked on the head of the list. /// This function is needed because when a fragment tree is transformed into a list, the tree structure itself /// is invalidated and cannot be used to free the fragments anymore. -static inline void rxFragmentDestroyList(struct UdpardFragment* const head, const RxMemory memory) +static void rxFragmentDestroyList(struct UdpardFragment* const head, const RxMemory memory) { struct UdpardFragment* handle = head; while (handle != NULL) @@ -925,7 +928,7 @@ static inline void rxFragmentDestroyList(struct UdpardFragment* const head, cons // -------------------------------------------------- RX SLOT -------------------------------------------------- -static inline void rxSlotFree(RxSlot* const self, const RxMemory memory) +static void rxSlotFree(RxSlot* const self, const RxMemory memory) { UDPARD_ASSERT(self != NULL); if (self->fragments != NULL) @@ -935,7 +938,7 @@ static inline void rxSlotFree(RxSlot* const self, const RxMemory memory) } } -static inline void rxSlotRestart(RxSlot* const self, const UdpardTransferID transfer_id, const RxMemory memory) +static void rxSlotRestart(RxSlot* const self, const UdpardTransferID transfer_id, const RxMemory memory) { UDPARD_ASSERT(self != NULL); rxSlotFree(self, memory); @@ -949,7 +952,7 @@ static inline void rxSlotRestart(RxSlot* const self, const UdpardTransferID tran /// This is a helper for rxSlotRestart that restarts the transfer for the next transfer-ID value. /// The transfer-ID increment is necessary to weed out duplicate transfers. -static inline void rxSlotRestartAdvance(RxSlot* const self, const RxMemory memory) +static void rxSlotRestartAdvance(RxSlot* const self, const RxMemory memory) { rxSlotRestart(self, self->transfer_id + 1U, memory); } @@ -961,15 +964,15 @@ typedef struct struct UdpardMemoryResource memory_fragment; } RxSlotUpdateContext; -static inline int_fast8_t rxSlotFragmentSearch(void* const user_reference, // NOSONAR Cavl API requires non-const. - const struct UdpardTreeNode* node) +static int_fast8_t rxSlotFragmentSearch(void* const user_reference, // NOSONAR Cavl API requires non-const. + const struct UdpardTreeNode* node) { UDPARD_ASSERT((user_reference != NULL) && (node != NULL)); return compare32(((const RxSlotUpdateContext*) user_reference)->frame_index, ((const RxFragmentTreeNode*) node)->this->frame_index); } -static inline struct UdpardTreeNode* rxSlotFragmentFactory(void* const user_reference) +static struct UdpardTreeNode* rxSlotFragmentFactory(void* const user_reference) { RxSlotUpdateContext* const ctx = (RxSlotUpdateContext*) user_reference; UDPARD_ASSERT((ctx != NULL) && (ctx->memory_fragment.allocate != NULL) && @@ -1001,7 +1004,7 @@ typedef struct /// See rxSlotEject() for details. /// The maximum recursion depth is ceil(1.44*log2(FRAME_INDEX_MAX+1)-0.328) = 45 levels. /// NOLINTNEXTLINE(misc-no-recursion) MISRA C:2012 rule 17.2 -static inline void rxSlotEjectFragment(RxFragment* const frag, RxSlotEjectContext* const ctx) +static void rxSlotEjectFragment(RxFragment* const frag, RxSlotEjectContext* const ctx) { UDPARD_ASSERT((frag != NULL) && (ctx != NULL)); if (frag->tree.base.lr[0] != NULL) @@ -1060,12 +1063,12 @@ static inline void rxSlotEjectFragment(RxFragment* const frag, RxSlotEjectContex /// There shall be at least one fragment (because a Cyphal transfer contains at least one frame). /// /// The return value indicates whether the transfer is valid (CRC is correct). -static inline bool rxSlotEject(size_t* const out_payload_size, - struct UdpardFragment* const out_payload_head, - RxFragmentTreeNode* const fragment_tree, - const size_t received_total_size, // With CRC. - const size_t extent, - const RxMemory memory) +static bool rxSlotEject(size_t* const out_payload_size, + struct UdpardFragment* const out_payload_head, + RxFragmentTreeNode* const fragment_tree, + const size_t received_total_size, // With CRC. + const size_t extent, + const RxMemory memory) { UDPARD_ASSERT((received_total_size >= TRANSFER_CRC_SIZE_BYTES) && (fragment_tree != NULL) && (out_payload_size != NULL) && (out_payload_head != NULL)); @@ -1094,7 +1097,7 @@ static inline bool rxSlotEject(size_t* const out_payload_size, } else { - *out_payload_head = (struct UdpardFragment){.next = NULL, .view = {0, NULL}, .origin = {0, NULL}}; + *out_payload_head = (struct UdpardFragment) {.next = NULL, .view = {0, NULL}, .origin = {0, NULL}}; } } else // The transfer turned out to be invalid. We have to free the fragments. Can't use the tree anymore. @@ -1106,7 +1109,7 @@ static inline bool rxSlotEject(size_t* const out_payload_size, /// Update the frame count discovery state in this transfer. /// Returns true on success, false if inconsistencies are detected and the slot should be restarted. -static inline bool rxSlotAccept_UpdateFrameCount(RxSlot* const self, const RxFrameBase frame) +static bool rxSlotAccept_UpdateFrameCount(RxSlot* const self, const RxFrameBase frame) { UDPARD_ASSERT((self != NULL) && (frame.payload.size > 0)); bool ok = true; @@ -1130,9 +1133,7 @@ static inline bool rxSlotAccept_UpdateFrameCount(RxSlot* const self, const RxFra /// Insert the fragment into the fragment tree. If it already exists, drop and free the duplicate. /// Returns 0 if the fragment is not needed, 1 if it is needed, negative on error. /// The fragment shall be deallocated unless the return value is 1. -static inline int_fast8_t rxSlotAccept_InsertFragment(RxSlot* const self, - const RxFrameBase frame, - const RxMemory memory) +static int_fast8_t rxSlotAccept_InsertFragment(RxSlot* const self, const RxFrameBase frame, const RxMemory memory) { UDPARD_ASSERT((self != NULL) && (frame.payload.size > 0) && (self->max_index <= self->eot_index) && (self->accepted_frames <= self->eot_index)); @@ -1164,11 +1165,11 @@ static inline int_fast8_t rxSlotAccept_InsertFragment(RxSlot* const self, /// Detect transfer completion. If complete, eject the payload from the fragment tree and check its CRC. /// The return value is passed over from rxSlotEject. -static inline int_fast8_t rxSlotAccept_FinalizeMaybe(RxSlot* const self, - size_t* const out_transfer_payload_size, - struct UdpardFragment* const out_transfer_payload_head, - const size_t extent, - const RxMemory memory) +static int_fast8_t rxSlotAccept_FinalizeMaybe(RxSlot* const self, + size_t* const out_transfer_payload_size, + struct UdpardFragment* const out_transfer_payload_head, + const size_t extent, + const RxMemory memory) { UDPARD_ASSERT((self != NULL) && (out_transfer_payload_size != NULL) && (out_transfer_payload_head != NULL) && (self->fragments != NULL)); @@ -1196,12 +1197,12 @@ static inline int_fast8_t rxSlotAccept_FinalizeMaybe(RxSlot* const /// This function will either move the frame payload into the session, or free it if it can't be used. /// Upon return, certain state fields may be overwritten, so the caller should not rely on them. /// Returns: 1 -- transfer available, payload written; 0 -- transfer not yet available; <0 -- error. -static inline int_fast8_t rxSlotAccept(RxSlot* const self, - size_t* const out_transfer_payload_size, - struct UdpardFragment* const out_transfer_payload_head, - const RxFrameBase frame, - const size_t extent, - const RxMemory memory) +static int_fast8_t rxSlotAccept(RxSlot* const self, + size_t* const out_transfer_payload_size, + struct UdpardFragment* const out_transfer_payload_head, + const RxFrameBase frame, + const size_t extent, + const RxMemory memory) { UDPARD_ASSERT((self != NULL) && (frame.payload.size > 0) && (out_transfer_payload_size != NULL) && (out_transfer_payload_head != NULL)); @@ -1237,7 +1238,7 @@ static inline int_fast8_t rxSlotAccept(RxSlot* const self, /// Whether the supplied transfer-ID is greater than all transfer-IDs in the RX slots. /// This indicates that the new transfer is not a duplicate and should be accepted. -static inline bool rxIfaceIsFutureTransferID(const RxIface* const self, const UdpardTransferID transfer_id) +static bool rxIfaceIsFutureTransferID(const RxIface* const self, const UdpardTransferID transfer_id) { bool is_future_tid = true; for (uint_fast8_t i = 0; i < RX_SLOT_COUNT; i++) // Expected to be unrolled by the compiler. @@ -1251,9 +1252,9 @@ static inline bool rxIfaceIsFutureTransferID(const RxIface* const self, const Ud /// Whether the time that has passed since the last accepted first frame of a transfer exceeds the TID timeout. /// This indicates that the transfer should be accepted even if its transfer-ID is not greater than all transfer-IDs /// in the RX slots. -static inline bool rxIfaceCheckTransferIDTimeout(const RxIface* const self, - const UdpardMicrosecond ts_usec, - const UdpardMicrosecond transfer_id_timeout_usec) +static bool rxIfaceCheckTransferIDTimeout(const RxIface* const self, + const UdpardMicrosecond ts_usec, + const UdpardMicrosecond transfer_id_timeout_usec) { // We use the RxIface state here because the RxSlot state is reset between transfers. // If there is reassembly in progress, we want to use the timestamps from these in-progress transfers, @@ -1275,7 +1276,7 @@ static inline bool rxIfaceCheckTransferIDTimeout(const RxIface* const self, /// If there is no such slot, tries again without the IN PROGRESS requirement. /// The purpose of this complicated dual check is to support the case where multiple slots have the same /// transfer-ID, which may occur with interleaved transfers. -static inline RxSlot* rxIfaceFindMatchingSlot(RxSlot slots[RX_SLOT_COUNT], const UdpardTransferID transfer_id) +static RxSlot* rxIfaceFindMatchingSlot(RxSlot slots[RX_SLOT_COUNT], const UdpardTransferID transfer_id) { RxSlot* slot = NULL; for (uint_fast8_t i = 0; i < RX_SLOT_COUNT; i++) @@ -1303,13 +1304,13 @@ static inline RxSlot* rxIfaceFindMatchingSlot(RxSlot slots[RX_SLOT_COUNT], const /// This function is invoked when a new datagram pertaining to a certain session is received on an interface. /// This function will either move the frame payload into the session, or free it if it cannot be made use of. /// Returns: 1 -- transfer available; 0 -- transfer not yet available; <0 -- error. -static inline int_fast8_t rxIfaceAccept(RxIface* const self, - const UdpardMicrosecond ts_usec, - const RxFrame frame, - const size_t extent, - const UdpardMicrosecond transfer_id_timeout_usec, - const RxMemory memory, - struct UdpardRxTransfer* const out_transfer) +static int_fast8_t rxIfaceAccept(RxIface* const self, + const UdpardMicrosecond ts_usec, + const RxFrame frame, + const size_t extent, + const UdpardMicrosecond transfer_id_timeout_usec, + const RxMemory memory, + struct UdpardRxTransfer* const out_transfer) { UDPARD_ASSERT((self != NULL) && (frame.base.payload.size > 0) && (out_transfer != NULL)); RxSlot* slot = rxIfaceFindMatchingSlot(self->slots, frame.meta.transfer_id); @@ -1371,7 +1372,7 @@ static inline int_fast8_t rxIfaceAccept(RxIface* const self, return result; } -static inline void rxIfaceInit(RxIface* const self, const RxMemory memory) +static void rxIfaceInit(RxIface* const self, const RxMemory memory) { UDPARD_ASSERT(self != NULL); memZero(sizeof(*self), self); @@ -1384,7 +1385,7 @@ static inline void rxIfaceInit(RxIface* const self, const RxMemory memory) } /// Frees the iface and all slots in it. The iface instance itself is not freed. -static inline void rxIfaceFree(RxIface* const self, const RxMemory memory) +static void rxIfaceFree(RxIface* const self, const RxMemory memory) { UDPARD_ASSERT(self != NULL); for (uint_fast8_t i = 0; i < RX_SLOT_COUNT; i++) @@ -1397,10 +1398,10 @@ static inline void rxIfaceFree(RxIface* const self, const RxMemory memory) /// Checks if the given transfer should be accepted. If not, the transfer is freed. /// Internal states are updated. -static inline bool rxSessionDeduplicate(struct UdpardInternalRxSession* const self, - const UdpardMicrosecond transfer_id_timeout_usec, - struct UdpardRxTransfer* const transfer, - const RxMemory memory) +static bool rxSessionDeduplicate(struct UdpardInternalRxSession* const self, + const UdpardMicrosecond transfer_id_timeout_usec, + struct UdpardRxTransfer* const transfer, + const RxMemory memory) { UDPARD_ASSERT((self != NULL) && (transfer != NULL)); const bool future_tid = (self->last_transfer_id == TRANSFER_ID_UNSET) || // @@ -1419,22 +1420,22 @@ static inline bool rxSessionDeduplicate(struct UdpardInternalRxSession* const se memFreePayload(memory.payload, transfer->payload.origin); rxFragmentDestroyList(transfer->payload.next, memory); transfer->payload_size = 0; - transfer->payload = (struct UdpardFragment){.next = NULL, - .view = {.size = 0, .data = NULL}, - .origin = {.size = 0, .data = NULL}}; + transfer->payload = (struct UdpardFragment) {.next = NULL, + .view = {.size = 0, .data = NULL}, + .origin = {.size = 0, .data = NULL}}; } return accept; } /// Takes ownership of the frame payload buffer. -static inline int_fast8_t rxSessionAccept(struct UdpardInternalRxSession* const self, - const uint_fast8_t redundant_iface_index, - const UdpardMicrosecond ts_usec, - const RxFrame frame, - const size_t extent, - const UdpardMicrosecond transfer_id_timeout_usec, - const RxMemory memory, - struct UdpardRxTransfer* const out_transfer) +static int_fast8_t rxSessionAccept(struct UdpardInternalRxSession* const self, + const uint_fast8_t redundant_iface_index, + const UdpardMicrosecond ts_usec, + const RxFrame frame, + const size_t extent, + const UdpardMicrosecond transfer_id_timeout_usec, + const RxMemory memory, + struct UdpardRxTransfer* const out_transfer) { UDPARD_ASSERT((self != NULL) && (redundant_iface_index < UDPARD_NETWORK_INTERFACE_COUNT_MAX) && (out_transfer != NULL)); @@ -1453,7 +1454,7 @@ static inline int_fast8_t rxSessionAccept(struct UdpardInternalRxSession* const return result; } -static inline void rxSessionInit(struct UdpardInternalRxSession* const self, const RxMemory memory) +static void rxSessionInit(struct UdpardInternalRxSession* const self, const RxMemory memory) { UDPARD_ASSERT(self != NULL); memZero(sizeof(*self), self); @@ -1469,14 +1470,14 @@ static inline void rxSessionInit(struct UdpardInternalRxSession* const self, con /// Frees all ifaces in the session, all children in the session tree recursively, and destroys the session itself. /// The maximum recursion depth is ceil(1.44*log2(UDPARD_NODE_ID_MAX+1)-0.328) = 23 levels. // NOLINTNEXTLINE(*-no-recursion) MISRA C:2012 rule 17.2 -static inline void rxSessionDestroyTree(struct UdpardInternalRxSession* const self, - const struct UdpardRxMemoryResources memory) +static void rxSessionDestroyTree(struct UdpardInternalRxSession* const self, + const struct UdpardRxMemoryResources memory) { if (self != NULL) { for (uint_fast8_t i = 0; i < UDPARD_NETWORK_INTERFACE_COUNT_MAX; i++) { - rxIfaceFree(&self->ifaces[i], (RxMemory){.fragment = memory.fragment, .payload = memory.payload}); + rxIfaceFree(&self->ifaces[i], (RxMemory) {.fragment = memory.fragment, .payload = memory.payload}); } for (uint_fast8_t i = 0; i < 2; i++) { @@ -1499,15 +1500,15 @@ typedef struct struct UdpardRxMemoryResources memory; } RxPortSessionSearchContext; -static inline int_fast8_t rxPortSessionSearch(void* const user_reference, // NOSONAR non-const API - const struct UdpardTreeNode* node) +static int_fast8_t rxPortSessionSearch(void* const user_reference, // NOSONAR non-const API + const struct UdpardTreeNode* node) { UDPARD_ASSERT((user_reference != NULL) && (node != NULL)); return compare32(((const RxPortSessionSearchContext*) user_reference)->remote_node_id, ((const struct UdpardInternalRxSession*) (const void*) node)->remote_node_id); } -static inline struct UdpardTreeNode* rxPortSessionFactory(void* const user_reference) // NOSONAR non-const API +static struct UdpardTreeNode* rxPortSessionFactory(void* const user_reference) // NOSONAR non-const API { const RxPortSessionSearchContext* const ctx = (const RxPortSessionSearchContext*) user_reference; UDPARD_ASSERT((ctx != NULL) && (ctx->remote_node_id <= UDPARD_NODE_ID_MAX)); @@ -1516,7 +1517,7 @@ static inline struct UdpardTreeNode* rxPortSessionFactory(void* const user_refer memAlloc(ctx->memory.session, sizeof(struct UdpardInternalRxSession)); if (session != NULL) { - rxSessionInit(session, (RxMemory){.payload = ctx->memory.payload, .fragment = ctx->memory.fragment}); + rxSessionInit(session, (RxMemory) {.payload = ctx->memory.payload, .fragment = ctx->memory.fragment}); session->remote_node_id = ctx->remote_node_id; out = &session->base; } @@ -1525,19 +1526,19 @@ static inline struct UdpardTreeNode* rxPortSessionFactory(void* const user_refer /// Accepts a frame into a port, possibly creating a new session along the way. /// The frame shall not be anonymous. Takes ownership of the frame payload buffer. -static inline int_fast8_t rxPortAccept(struct UdpardRxPort* const self, - const uint_fast8_t redundant_iface_index, - const UdpardMicrosecond ts_usec, - const RxFrame frame, - const struct UdpardRxMemoryResources memory, - struct UdpardRxTransfer* const out_transfer) +static int_fast8_t rxPortAccept(struct UdpardRxPort* const self, + const uint_fast8_t redundant_iface_index, + const UdpardMicrosecond ts_usec, + const RxFrame frame, + const struct UdpardRxMemoryResources memory, + struct UdpardRxTransfer* const out_transfer) { UDPARD_ASSERT((self != NULL) && (redundant_iface_index < UDPARD_NETWORK_INTERFACE_COUNT_MAX) && (out_transfer != NULL) && (frame.meta.src_node_id != UDPARD_NODE_ID_UNSET)); int_fast8_t result = 0; struct UdpardInternalRxSession* const session = (struct UdpardInternalRxSession*) (void*) cavlSearch((struct UdpardTreeNode**) &self->sessions, - &(RxPortSessionSearchContext){.remote_node_id = frame.meta.src_node_id, .memory = memory}, + &(RxPortSessionSearchContext) {.remote_node_id = frame.meta.src_node_id, .memory = memory}, &rxPortSessionSearch, &rxPortSessionFactory); if (session != NULL) @@ -1549,7 +1550,7 @@ static inline int_fast8_t rxPortAccept(struct UdpardRxPort* const self frame, self->extent, self->transfer_id_timeout_usec, - (RxMemory){.payload = memory.payload, .fragment = memory.fragment}, + (RxMemory) {.payload = memory.payload, .fragment = memory.fragment}, out_transfer); } else // Failed to allocate a new session. @@ -1562,10 +1563,10 @@ static inline int_fast8_t rxPortAccept(struct UdpardRxPort* const self /// A special case of rxPortAccept() for anonymous transfers. Accepts all transfers unconditionally. /// Does not allocate new memory. Takes ownership of the frame payload buffer. -static inline int_fast8_t rxPortAcceptAnonymous(const UdpardMicrosecond ts_usec, - const RxFrame frame, - const struct UdpardMemoryDeleter memory, - struct UdpardRxTransfer* const out_transfer) +static int_fast8_t rxPortAcceptAnonymous(const UdpardMicrosecond ts_usec, + const RxFrame frame, + const struct UdpardMemoryDeleter memory, + struct UdpardRxTransfer* const out_transfer) { UDPARD_ASSERT((out_transfer != NULL) && (frame.meta.src_node_id == UDPARD_NODE_ID_UNSET)); int_fast8_t result = 0; @@ -1597,12 +1598,12 @@ static inline int_fast8_t rxPortAcceptAnonymous(const UdpardMicrosecond /// Accepts a raw frame and, if valid, passes it on to rxPortAccept() for further processing. /// Takes ownership of the frame payload buffer. -static inline int_fast8_t rxPortAcceptFrame(struct UdpardRxPort* const self, - const uint_fast8_t redundant_iface_index, - const UdpardMicrosecond ts_usec, - const struct UdpardMutablePayload datagram_payload, - const struct UdpardRxMemoryResources memory, - struct UdpardRxTransfer* const out_transfer) +static int_fast8_t rxPortAcceptFrame(struct UdpardRxPort* const self, + const uint_fast8_t redundant_iface_index, + const UdpardMicrosecond ts_usec, + const struct UdpardMutablePayload datagram_payload, + const struct UdpardRxMemoryResources memory, + struct UdpardRxTransfer* const out_transfer) { int_fast8_t result = 0; RxFrame frame = {0}; @@ -1624,7 +1625,7 @@ static inline int_fast8_t rxPortAcceptFrame(struct UdpardRxPort* const return result; } -static inline void rxPortInit(struct UdpardRxPort* const self) +static void rxPortInit(struct UdpardRxPort* const self) { memZero(sizeof(*self), self); self->extent = SIZE_MAX; // Unlimited extent by default. @@ -1632,22 +1633,22 @@ static inline void rxPortInit(struct UdpardRxPort* const self) self->sessions = NULL; } -static inline void rxPortFree(struct UdpardRxPort* const self, const struct UdpardRxMemoryResources memory) +static void rxPortFree(struct UdpardRxPort* const self, const struct UdpardRxMemoryResources memory) { rxSessionDestroyTree(self->sessions, memory); self->sessions = NULL; } -static inline int_fast8_t rxRPCSearch(void* const user_reference, // NOSONAR Cavl API requires non-const. - const struct UdpardTreeNode* node) +static int_fast8_t rxRPCSearch(void* const user_reference, // NOSONAR Cavl API requires non-const. + const struct UdpardTreeNode* node) { UDPARD_ASSERT((user_reference != NULL) && (node != NULL)); return compare32(((const struct UdpardRxRPCPort*) user_reference)->service_id, ((const struct UdpardRxRPCPort*) (const void*) node)->service_id); } -static inline int_fast8_t rxRPCSearchByServiceID(void* const user_reference, // NOSONAR Cavl API requires non-const. - const struct UdpardTreeNode* node) +static int_fast8_t rxRPCSearchByServiceID(void* const user_reference, // NOSONAR Cavl API requires non-const. + const struct UdpardTreeNode* node) { UDPARD_ASSERT((user_reference != NULL) && (node != NULL)); return compare32(*(const UdpardPortID*) user_reference, @@ -1662,7 +1663,7 @@ void udpardRxFragmentFree(const struct UdpardFragment head, { // The head is not heap-allocated so not freed. memFreePayload(memory_payload, head.origin); // May be NULL, is okay. - rxFragmentDestroyList(head.next, (RxMemory){.fragment = memory_fragment, .payload = memory_payload}); + rxFragmentDestroyList(head.next, (RxMemory) {.fragment = memory_fragment, .payload = memory_payload}); } int_fast8_t udpardRxSubscriptionInit(struct UdpardRxSubscription* const self, diff --git a/libudpard/udpard.h b/libudpard/udpard.h index 0df85b9..2c8a5e1 100644 --- a/libudpard/udpard.h +++ b/libudpard/udpard.h @@ -173,7 +173,8 @@ /// /// Typically, if block pool allocators are used, the following block sizes should be served: /// -/// - (MTU+library overhead) blocks for the TX and RX pipelines (usually less than 2048 bytes); +/// - MTU sized blocks for the TX and RX pipelines (usually less than 2048 bytes); +/// - TX fragment item sized blocks for the TX pipeline (less than 128 bytes). /// - RX session object sized blocks for the RX pipeline (less than 512 bytes); /// - RX fragment handle sized blocks for the RX pipeline (less than 128 bytes). /// @@ -200,7 +201,7 @@ extern "C" { /// Semantic version of this library (not the Cyphal specification). /// API will be backward compatible within the same major version. -#define UDPARD_VERSION_MAJOR 1 +#define UDPARD_VERSION_MAJOR 2 #define UDPARD_VERSION_MINOR 0 /// The version number of the Cyphal specification implemented by this library. @@ -373,14 +374,34 @@ struct UdpardMemoryResource // ================================================= TX PIPELINE ================================================= // ===================================================================================================================== +/// The set of memory resources is used per a TX pipeline instance. +/// These are used to serve the memory needs of the library to keep state while assembling outgoing frames. +/// Several memory resources are provided to enable fine control over the allocated memory. +/// +/// A TX queue uses these memory resources for allocating the enqueued items (UDP datagrams). +/// There are exactly two allocations per enqueued item: +/// - the first for bookkeeping purposes (UdpardTxItem) +/// - second for payload storage (the frame data) +/// In a simple application, there would be just one memory resource shared by all parts of the library. +/// If the application knows its MTU, it can use block allocation to avoid extrinsic fragmentation. +/// +struct UdpardTxMemoryResources +{ + /// The fragment handles are allocated per payload fragment; each handle contains a pointer to its fragment. + /// Each instance is of a very small fixed size, so a trivial zero-fragmentation block allocator is enough. + struct UdpardMemoryResource fragment; + + /// The payload fragments are allocated per payload frame; each payload fragment is at most MTU-sized buffer, + /// so a trivial zero-fragmentation MTU-sized block allocator is enough if MTU is known in advance. + struct UdpardMemoryResource payload; +}; + /// The transmission pipeline is a prioritized transmission queue that keeps UDP datagrams (aka transport frames) /// destined for transmission via one network interface. /// Applications with redundant network interfaces are expected to have one instance of this type per interface. /// Applications that are not interested in transmission may have zero such instances. /// /// All operations are logarithmic in complexity on the number of enqueued items. -/// There is exactly one memory allocation per element; -/// the size of each allocation is sizeof(UdpardTxItem) plus the size of the datagram. /// /// Once initialized, instances cannot be copied. /// @@ -424,12 +445,8 @@ struct UdpardTx /// The value can be changed arbitrarily at any time between enqueue operations. uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U]; - /// The memory resource used by this queue for allocating the enqueued items (UDP datagrams). - /// There is exactly one allocation per enqueued item, each allocation contains both the UdpardTxItem - /// and its payload, hence the size is variable. - /// In a simple application there would be just one memory resource shared by all parts of the library. - /// If the application knows its MTU, it can use block allocation to avoid extrinsic fragmentation. - struct UdpardMemoryResource memory; + /// Refer to UdpardTxMemoryResources. + struct UdpardTxMemoryResources memory; /// The number of frames that are currently contained in the queue, initially zero. /// READ-ONLY @@ -443,7 +460,8 @@ struct UdpardTx /// One transport frame (UDP datagram) stored in the UdpardTx transmission queue along with its metadata. /// The datagram should be sent to the indicated UDP/IP endpoint with the specified DSCP value. /// The datagram should be discarded (transmission aborted) if the deadline has expired. -/// All fields are READ-ONLY. +/// All fields are READ-ONLY except the mutable `datagram_payload` field, which could be nullified to indicate +/// a transfer of the payload memory ownership to somewhere else. struct UdpardTxItem { /// Internal use only; do not access this field. @@ -464,6 +482,9 @@ struct UdpardTxItem /// LibUDPard selects the DSCP value based on the transfer priority level and the configured DSCP mapping. uint_least8_t dscp; + /// Holds the original transfer priority level (before DSCP mapping, see above `dscp`). + enum UdpardPriority priority; + /// This UDP/IP datagram compiled by libudpard should be sent to this endpoint. /// The endpoint is always at a multicast address. struct UdpardUDPIPEndpoint destination; @@ -490,10 +511,10 @@ struct UdpardTxItem /// /// The return value is zero on success, otherwise it is a negative error code. /// The time complexity is constant. This function does not invoke the dynamic memory manager. -int_fast8_t udpardTxInit(struct UdpardTx* const self, - const UdpardNodeID* const local_node_id, - const size_t queue_capacity, - const struct UdpardMemoryResource memory); +int_fast8_t udpardTxInit(struct UdpardTx* const self, + const UdpardNodeID* const local_node_id, + const size_t queue_capacity, + const struct UdpardTxMemoryResources memory); /// This function serializes a message transfer into a sequence of UDP datagrams and inserts them into the prioritized /// transmission queue at the appropriate position. Afterwards, the application is supposed to take the enqueued frames @@ -547,10 +568,13 @@ int_fast8_t udpardTxInit(struct UdpardTx* const self, /// In such cases, all frames allocated for this transfer (if any) will be deallocated automatically. /// In other words, either all frames of the transfer are enqueued successfully, or none are. /// -/// The memory allocation requirement is one allocation per datagram: -/// a single-frame transfer takes one allocation; a multi-frame transfer of N frames takes N allocations. -/// The size of each allocation is (sizeof(UdpardTxItem) + MTU) except for the last datagram where the payload may be -/// smaller than the MTU. +/// The memory allocation requirement is two allocations per datagram: +/// a single-frame transfer takes two allocations; a multi-frame transfer of N frames takes N*2 allocations. +/// In each pair of allocations: +/// - the first allocation is for `UdpardTxItem`; the size is `sizeof(UdpardTxItem)`; +/// the TX queue `memory.fragment` memory resource is used for this allocation (and later for deallocation); +/// - the second allocation is for payload storage (the frame data) - size is normally MTU but could be less for +/// the last frame of the transfer; the TX queue `memory.payload` memory resource is used for this allocation. /// /// The time complexity is O(p + log e), where p is the amount of payload in the transfer, and e is the number of /// frames already enqueued in the transmission queue. @@ -613,35 +637,45 @@ int32_t udpardTxRespond(struct UdpardTx* const self, /// /// If the queue is non-empty, the returned value is a pointer to its top element (i.e., the next item to transmit). /// The returned pointer points to an object allocated in the dynamic storage; it should be eventually freed by the -/// application by calling udpardTxFree with UdpardTx::memory. The memory shall not be freed before the item is removed +/// application by calling `udpardTxFree`. The memory shall not be freed before the item is removed /// from the queue by calling udpardTxPop; this is because until udpardTxPop is executed, the library retains /// ownership of the item. The pointer retains validity until explicitly freed by the application; in other words, /// calling udpardTxPop does not invalidate the object. /// -/// The payload buffer is located shortly after the object itself, in the same memory fragment. The application shall -/// not attempt to free it. -/// /// Calling functions that modify the queue may cause the next invocation to return a different pointer. /// +/// The payload buffer is allocated in the dynamic storage of the queue. The application may transfer ownership of +/// the payload to a different application component (f.e. to transmission media) by copying the pointer and then +/// (if the ownership transfer was accepted) by nullifying `datagram_payload` fields of the frame (`size` & `data`). +/// If these fields stay with their original values, the `udpardTxFree` (after proper `udpardTxPop` of course) will +/// deallocate the payload buffer. In any case, the payload has to be eventually deallocated by using the TX queue +/// `memory.payload` memory resource. It will be automatically done by the `udpardTxFree` (if the payload still +/// stays in the item), OR if moved, it is the responsibility of the application to eventually (f.e. at the end of +/// transmission) deallocate the memory with the TX queue `memory.payload` memory resource. +/// Note that the mentioned above nullification of the `datagram_payload` fields is the +/// only reason why a returned TX item pointer is mutable. It was constant in the past (before v2), +/// but it was changed to be mutable to allow the payload ownership transfer. +/// /// The time complexity is logarithmic of the queue size. This function does not invoke the dynamic memory manager. -const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self); +struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self); /// This function transfers the ownership of the specified item of the prioritized transmission queue from the queue /// to the application. The item does not necessarily need to be the top one -- it is safe to dequeue any item. /// The item is dequeued but not invalidated; it is the responsibility of the application to deallocate its memory -/// later. The memory SHALL NOT be deallocated UNTIL this function is invoked. +/// later. The memory SHALL NOT be deallocated UNTIL this function is invoked (use `udpardTxFree` helper). /// The function returns the same pointer that it is given except that it becomes mutable. /// /// If any of the arguments are NULL, the function has no effect and returns NULL. /// /// The time complexity is logarithmic of the queue size. This function does not invoke the dynamic memory manager. -struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, const struct UdpardTxItem* const item); +struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, struct UdpardTxItem* const item); -/// This is a simple helper that frees the memory allocated for the item with the correct size. -/// It is needed because the application does not have access to the required context to compute the size. -/// If the chosen allocator does not leverage the size information, the deallocation function can be invoked directly. +/// This is a simple helper that frees the memory allocated for the item and its payload, +/// using the correct sizes and memory resources. /// If the item argument is NULL, the function has no effect. The time complexity is constant. -void udpardTxFree(const struct UdpardMemoryResource memory, struct UdpardTxItem* const item); +/// If the item frame payload is NULL then it is assumed that the payload buffer was already freed, +/// or moved to a different owner (f.e. to media layer). +void udpardTxFree(const struct UdpardTxMemoryResources memory, struct UdpardTxItem* const item); // ===================================================================================================================== // ================================================= RX PIPELINE ================================================= diff --git a/tests/.clang-tidy b/tests/.clang-tidy index 1e318f0..657d99d 100644 --- a/tests/.clang-tidy +++ b/tests/.clang-tidy @@ -35,6 +35,8 @@ Checks: >- -cppcoreguidelines-avoid-const-or-ref-data-members, -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-reinterpret-cast, + -boost-use-ranges, + -modernize-use-ranges, -*-no-malloc, -cert-msc30-c, -cert-msc50-cpp, diff --git a/tests/src/test_e2e.cpp b/tests/src/test_e2e.cpp index d3437aa..8ea7800 100644 --- a/tests/src/test_e2e.cpp +++ b/tests/src/test_e2e.cpp @@ -73,7 +73,10 @@ void testPubSub() instrumentedAllocatorNew(&alloc_rx_session); instrumentedAllocatorNew(&alloc_rx_fragment); instrumentedAllocatorNew(&alloc_rx_payload); - const auto mem_tx = instrumentedAllocatorMakeMemoryResource(&alloc_tx); + const UdpardTxMemoryResources mem_tx{ + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + }; const UdpardRxMemoryResources mem_rx{ .session = instrumentedAllocatorMakeMemoryResource(&alloc_rx_session), .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_rx_fragment), @@ -152,7 +155,7 @@ void testPubSub() makePayload(Dark), nullptr)); TEST_ASSERT_EQUAL(7, tx.queue_size); - TEST_ASSERT_EQUAL(7, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(7 * 2ULL, alloc_tx.allocated_fragments); // Transmit the enqueued frames by pushing them into the subscribers. // Here we pop the frames one by one ensuring that they come out in the correct order. @@ -161,7 +164,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_session.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc_rx_fragment.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); - const UdpardTxItem* tx_item = udpardTxPeek(&tx); + UdpardTxItem* tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); TEST_ASSERT_EQUAL(sub.at(1).udp_ip_endpoint.ip_address, tx_item->destination.ip_address); TEST_ASSERT_NULL(tx_item->next_in_transfer); @@ -212,7 +215,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(6, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc_tx.allocated_fragments); // Second transfer. tx_item = udpardTxPeek(&tx); @@ -247,7 +250,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(5, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc_tx.allocated_fragments); // Third transfer. This one is anonymous. tx_item = udpardTxPeek(&tx); @@ -282,7 +285,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(4, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc_tx.allocated_fragments); // Fourth transfer. This one contains multiple frames. We process them one-by-one. // Frame #0. @@ -305,7 +308,7 @@ void testPubSub() TEST_ASSERT_EQUAL(1, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(3, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc_tx.allocated_fragments); // Frame #1. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -327,7 +330,7 @@ void testPubSub() TEST_ASSERT_EQUAL(2, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(2, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc_tx.allocated_fragments); // Frame #2. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -349,7 +352,7 @@ void testPubSub() TEST_ASSERT_EQUAL(3, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(1, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc_tx.allocated_fragments); // Frame #3. This is the last frame of the transfer. The payload is truncated, see the extent. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -410,7 +413,10 @@ void testRPC() instrumentedAllocatorNew(&alloc_rx_session); instrumentedAllocatorNew(&alloc_rx_fragment); instrumentedAllocatorNew(&alloc_rx_payload); - const auto mem_tx = instrumentedAllocatorMakeMemoryResource(&alloc_tx); + const UdpardTxMemoryResources mem_tx{ + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + }; const UdpardRxMemoryResources mem_rx{ .session = instrumentedAllocatorMakeMemoryResource(&alloc_rx_session), .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_rx_fragment), @@ -472,7 +478,7 @@ void testRPC() TEST_ASSERT_EQUAL(0, alloc_rx_session.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc_rx_fragment.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); - const UdpardTxItem* tx_item = udpardTxPeek(&tx); + UdpardTxItem* tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); TEST_ASSERT_EQUAL(udp_ip_endpoint.ip_address, tx_item->destination.ip_address); TEST_ASSERT_NULL(tx_item->next_in_transfer); @@ -529,7 +535,7 @@ void testRPC() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(1, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc_tx.allocated_fragments); // Second transfer. tx_item = udpardTxPeek(&tx); diff --git a/tests/src/test_intrusive_rx.c b/tests/src/test_intrusive_rx.c index 74ce5a1..cb4f66f 100644 --- a/tests/src/test_intrusive_rx.c +++ b/tests/src/test_intrusive_rx.c @@ -51,8 +51,8 @@ static RxFragment* makeRxFragmentString(const RxMemory memory, const size_t sz = strlen(payload); return makeRxFragment(memory, frame_index, - (struct UdpardPayload){.data = payload, .size = sz}, - (struct UdpardMutablePayload){.data = (void*) payload, .size = sz}, + (struct UdpardPayload) {.data = payload, .size = sz}, + (struct UdpardMutablePayload) {.data = (void*) payload, .size = sz}, parent); } @@ -103,8 +103,8 @@ static RxFrameBase makeRxFrameBaseString(InstrumentedAllocator* const memory, return makeRxFrameBase(memory, frame_index, end_of_transfer, - (struct UdpardPayload){.data = payload, .size = strlen(payload)}, - (struct UdpardMutablePayload){.data = (void*) payload, .size = strlen(payload)}); + (struct UdpardPayload) {.data = payload, .size = strlen(payload)}, + (struct UdpardMutablePayload) {.data = (void*) payload, .size = strlen(payload)}); } static RxFrame makeRxFrameString(InstrumentedAllocator* const memory, @@ -113,13 +113,13 @@ static RxFrame makeRxFrameString(InstrumentedAllocator* const memory, const bool end_of_transfer, const char* const payload) { - return (RxFrame){.base = makeRxFrameBaseString(memory, frame_index, end_of_transfer, payload), .meta = meta}; + return (RxFrame) {.base = makeRxFrameBaseString(memory, frame_index, end_of_transfer, payload), .meta = meta}; } static RxMemory makeRxMemory(InstrumentedAllocator* const fragment, InstrumentedAllocator* const payload) { - return (RxMemory){.fragment = instrumentedAllocatorMakeMemoryResource(fragment), - .payload = instrumentedAllocatorMakeMemoryDeleter(payload)}; + return (RxMemory) {.fragment = instrumentedAllocatorMakeMemoryResource(fragment), + .payload = instrumentedAllocatorMakeMemoryDeleter(payload)}; } static struct UdpardMutablePayload makeDatagramPayload(InstrumentedAllocator* const memory, @@ -151,7 +151,7 @@ static struct UdpardMutablePayload makeDatagramPayloadString(InstrumentedAllocat meta, frame_index, end_of_transfer, - (struct UdpardPayload){.data = string, .size = strlen(string)}); + (struct UdpardPayload) {.data = string, .size = strlen(string)}); } static struct UdpardMutablePayload makeDatagramPayloadSingleFrame(InstrumentedAllocator* const memory, @@ -163,8 +163,8 @@ static struct UdpardMutablePayload makeDatagramPayloadSingleFrame(InstrumentedAl meta, 0, true, - (struct UdpardPayload){.data = payload.data, - .size = payload.size + TRANSFER_CRC_SIZE_BYTES}); + (struct UdpardPayload) {.data = payload.data, + .size = payload.size + TRANSFER_CRC_SIZE_BYTES}); TEST_PANIC_UNLESS(pld.size == (payload.size + HEADER_SIZE_BYTES + TRANSFER_CRC_SIZE_BYTES)); txSerializeU32(((byte_t*) pld.data) + HEADER_SIZE_BYTES + payload.size, transferCRCCompute(payload.size, payload.data)); @@ -177,7 +177,7 @@ static struct UdpardMutablePayload makeDatagramPayloadSingleFrameString(Instrume { return makeDatagramPayloadSingleFrame(memory, meta, - (struct UdpardPayload){.data = payload, .size = strlen(payload)}); + (struct UdpardPayload) {.data = payload, .size = strlen(payload)}); } // -------------------------------------------------- MISC -------------------------------------------------- @@ -212,7 +212,7 @@ static void testParseFrameValidMessage(void) 254, 15, 220, 186, 57, 48, 0, 0, 0, 0, 30, 179, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); TEST_ASSERT_EQUAL_UINT64(UdpardPriorityFast, rxf.meta.priority); TEST_ASSERT_EQUAL_UINT64(2345, rxf.meta.src_node_id); TEST_ASSERT_EQUAL_UINT64(UDPARD_NODE_ID_UNSET, rxf.meta.dst_node_id); @@ -235,7 +235,7 @@ static void testParseFrameValidRPCService(void) 254, 15, 220, 186, 254, 25, 0, 0, 0, 0, 173, 122, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); TEST_ASSERT_EQUAL_UINT64(UdpardPriorityFast, rxf.meta.priority); TEST_ASSERT_EQUAL_UINT64(2345, rxf.meta.src_node_id); TEST_ASSERT_EQUAL_UINT64(4567, rxf.meta.dst_node_id); @@ -257,7 +257,7 @@ static void testParseFrameValidMessageAnonymous(void) 254, 15, 220, 186, 0, 0, 0, 128, 0, 0, 168, 92, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); TEST_ASSERT_EQUAL_UINT64(UdpardPriorityFast, rxf.meta.priority); TEST_ASSERT_EQUAL_UINT64(UDPARD_NODE_ID_UNSET, rxf.meta.src_node_id); TEST_ASSERT_EQUAL_UINT64(UDPARD_NODE_ID_UNSET, rxf.meta.dst_node_id); @@ -277,7 +277,7 @@ static void testParseFrameRPCServiceAnonymous(void) 254, 15, 220, 186, 254, 25, 0, 0, 0, 0, 75, 79, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameRPCServiceBroadcast(void) @@ -286,7 +286,7 @@ static void testParseFrameRPCServiceBroadcast(void) 254, 15, 220, 186, 254, 25, 0, 0, 0, 0, 248, 152, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameAnonymousNonSingleFrame(void) @@ -295,7 +295,7 @@ static void testParseFrameAnonymousNonSingleFrame(void) 254, 15, 220, 186, 0, 0, 0, 0, 0, 0, 147, 6, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameBadHeaderCRC(void) @@ -304,7 +304,7 @@ static void testParseFrameBadHeaderCRC(void) 254, 15, 220, 186, 57, 48, 0, 0, 0, 0, 30, 180, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameUnknownHeaderVersion(void) @@ -316,20 +316,20 @@ static void testParseFrameUnknownHeaderVersion(void) 254, 15, 220, 186, 57, 48, 0, 0, 0, 0, 141, 228, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameHeaderWithoutPayload(void) { byte_t data[] = {1, 2, 41, 9, 255, 255, 230, 29, 13, 240, 221, 224, 254, 15, 220, 186, 57, 48, 0, 0, 0, 0, 30, 179}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } static void testParseFrameEmpty(void) { RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = "", .size = 0}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = "", .size = 0}, &rxf)); } static void testParseFrameInvalidTransferID(void) @@ -339,7 +339,7 @@ static void testParseFrameInvalidTransferID(void) 255, 255, 255, 255, 57, 48, 0, 0, 0, 0, 42, 107, // 'a', 'b', 'c'}; RxFrame rxf = {0}; - TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, &rxf)); + TEST_ASSERT_FALSE(rxParseFrame((struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, &rxf)); } // -------------------------------------------------- SLOT -------------------------------------------------- @@ -385,21 +385,21 @@ static void testSlotRestartNonEmpty(void) // .fragments = &makeRxFragment(mem, 1, - (struct UdpardPayload){.data = &data[2], .size = 2}, - (struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, + (struct UdpardPayload) {.data = &data[2], .size = 2}, + (struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, NULL) ->tree, }; slot.fragments->base.lr[0] = &makeRxFragment(mem, 0, - (struct UdpardPayload){.data = &data[1], .size = 1}, - (struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, + (struct UdpardPayload) {.data = &data[1], .size = 1}, + (struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, slot.fragments) ->tree.base; slot.fragments->base.lr[1] = &makeRxFragment(mem, 2, - (struct UdpardPayload){.data = &data[3], .size = 3}, - (struct UdpardMutablePayload){.data = data, .size = sizeof(data)}, + (struct UdpardPayload) {.data = &data[3], .size = 3}, + (struct UdpardMutablePayload) {.data = data, .size = sizeof(data)}, slot.fragments) ->tree.base; // Initialization done, ensure the memory utilization is as we expect. @@ -1206,11 +1206,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 1234567890, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1234, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1234, - .transfer_id = 0x1122334455667788U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1234, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1234, + .transfer_id = 0x1122334455667788U}, 0, true, "I am a tomb." @@ -1242,11 +1242,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 1234567891, // different timestamp but ignored anyway makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1234, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1234, - .transfer_id = 0x1122334455667788U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1234, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1234, + .transfer_id = 0x1122334455667788U}, 0, true, "I am a tomb." @@ -1268,11 +1268,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 1234567892, // different timestamp but ignored anyway makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1234, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1234, - .transfer_id = 0x1122334455667789U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1234, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1234, + .transfer_id = 0x1122334455667789U}, 0, true, "I am a tomb." @@ -1295,11 +1295,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 1234567893, // different timestamp but ignored anyway makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1234, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1234, - .transfer_id = 0x1122334455667790U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1234, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1234, + .transfer_id = 0x1122334455667790U}, 0, true, "I am a tomb." @@ -1325,11 +1325,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 2000000020, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 2, true, "A2" @@ -1348,11 +1348,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 2000000010, // Transfer-ID timeout. makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x2222, - .transfer_id = 1001U}, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x2222, + .transfer_id = 1001U}, 1, true, "B1" @@ -1371,11 +1371,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 2000000030, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 0, false, "A0"), @@ -1393,11 +1393,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 2000000040, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x2222, - .transfer_id = 1001U}, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x2222, + .transfer_id = 1001U}, 0, false, "B0"), @@ -1429,11 +1429,11 @@ static void testIfaceAcceptA(void) rxIfaceAccept(&iface, 2000000050, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 1, false, "A1"), @@ -1496,11 +1496,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000020, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 2, true, "A2" @@ -1519,11 +1519,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000010, // TIME REORDERING -- lower than previous. makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x2222, - .transfer_id = 1001U}, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x2222, + .transfer_id = 1001U}, 1, true, "B1" @@ -1542,11 +1542,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000030, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 0, false, "A0"), @@ -1564,11 +1564,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000040, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x3333, - .transfer_id = 1002U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x3333, + .transfer_id = 1002U}, 0, false, "C0"), @@ -1586,11 +1586,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000050, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x2222, - .transfer_id = 1001U}, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x2222, + .transfer_id = 1001U}, 0, false, "B0"), @@ -1608,11 +1608,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000050, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x1111, - .transfer_id = 1000U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x1111, + .transfer_id = 1000U}, 1, false, "A1"), @@ -1644,11 +1644,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000060, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x3333, - .transfer_id = 1002U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x3333, + .transfer_id = 1002U}, 0, false, "C0 DUPLICATE"), @@ -1666,11 +1666,11 @@ static void testIfaceAcceptB(void) rxIfaceAccept(&iface, 2000000070, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityHigh, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0x3333, - .transfer_id = 1002U}, + (TransferMetadata) {.priority = UdpardPriorityHigh, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0x3333, + .transfer_id = 1002U}, 1, true, "C1" @@ -1734,11 +1734,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000010, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityOptional, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xA}, + (TransferMetadata) {.priority = UdpardPriorityOptional, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xA}, 0, false, "A0"), @@ -1756,11 +1756,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000020, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 0, false, "B0"), @@ -1778,11 +1778,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000030, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityOptional, - .src_node_id = 1111, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xA}, + (TransferMetadata) {.priority = UdpardPriorityOptional, + .src_node_id = 1111, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xA}, 1, true, "A1" @@ -1811,11 +1811,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000040, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xC}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xC}, 0, false, "C0"), @@ -1833,11 +1833,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000050, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 1, true, "B1" @@ -1868,11 +1868,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000060, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xC}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xC}, 1, true, "C1" @@ -1902,11 +1902,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000070, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 0, false, "B0"), @@ -1921,11 +1921,11 @@ static void testIfaceAcceptC(void) rxIfaceAccept(&iface, 2000000080, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 0, true, "B0" @@ -2051,11 +2051,11 @@ static void testSessionAcceptA(void) 1, 10000000, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 0, true, "Z\xBA\xA1\xBAh"), @@ -2075,11 +2075,11 @@ static void testSessionAcceptA(void) 0, 10000010, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, 0, true, "Z\xBA\xA1\xBAh"), @@ -2096,11 +2096,11 @@ static void testSessionAcceptA(void) 2, 12000020, makeRxFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityExceptional, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xC}, + (TransferMetadata) {.priority = UdpardPriorityExceptional, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xC}, 0, true, "Z\xBA\xA1\xBAh"), @@ -2140,11 +2140,11 @@ static inline void testPortAcceptFrameA(void) 1, 10000000, makeDatagramPayloadSingleFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = 2222, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xB}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = 2222, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xB}, "When will the collapse of space in the vicinity of the " "Solar System into two dimensions cease?"), mem, @@ -2174,11 +2174,11 @@ static inline void testPortAcceptFrameA(void) 0, 10000010, makeDatagramPayloadSingleFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = 3333, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xC}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = 3333, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xC}, "It will never cease."), mem, &transfer)); @@ -2206,11 +2206,11 @@ static inline void testPortAcceptFrameA(void) 2, 10000020, makeDatagramPayloadSingleFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = 4444, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xD}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = 4444, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xD}, "Cheng Xin shuddered."), mem, &transfer)); @@ -2226,11 +2226,11 @@ static inline void testPortAcceptFrameA(void) 2, 10000030, makeDatagramPayloadSingleFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = UDPARD_NODE_ID_UNSET, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xD}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = UDPARD_NODE_ID_UNSET, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xD}, "Cheng Xin shuddered."), mem, &transfer)); @@ -2254,11 +2254,11 @@ static inline void testPortAcceptFrameA(void) { // Bad CRC. struct UdpardMutablePayload datagram = makeDatagramPayloadSingleFrameString(&mem_payload, // - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = UDPARD_NODE_ID_UNSET, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xE}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = UDPARD_NODE_ID_UNSET, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xE}, "You are scared? Do you think that in this galaxy, in this universe, " "only the Solar System is collapsing into two dimensions? Haha..."); *(((byte_t*) datagram.data) + HEADER_SIZE_BYTES) = 0x00; // Corrupt the payload, CRC invalid. @@ -2270,18 +2270,18 @@ static inline void testPortAcceptFrameA(void) { // No payload (transfer CRC is always required). byte_t* const payload = instrumentedAllocatorAllocate(&mem_payload, HEADER_SIZE_BYTES); (void) txSerializeHeader(payload, - (TransferMetadata){.priority = UdpardPriorityImmediate, - .src_node_id = UDPARD_NODE_ID_UNSET, - .dst_node_id = UDPARD_NODE_ID_UNSET, - .data_specifier = 0, - .transfer_id = 0xE}, + (TransferMetadata) {.priority = UdpardPriorityImmediate, + .src_node_id = UDPARD_NODE_ID_UNSET, + .dst_node_id = UDPARD_NODE_ID_UNSET, + .data_specifier = 0, + .transfer_id = 0xE}, 0, true); TEST_ASSERT_EQUAL(0, rxPortAcceptFrame(&port, 0, 10000050, - (struct UdpardMutablePayload){.size = HEADER_SIZE_BYTES, .data = payload}, + (struct UdpardMutablePayload) {.size = HEADER_SIZE_BYTES, .data = payload}, mem, &transfer)); TEST_ASSERT_EQUAL(2, mem_session.allocated_fragments); @@ -2295,10 +2295,10 @@ static inline void testPortAcceptFrameA(void) 0, 10000060, (struct - UdpardMutablePayload){.size = HEADER_SIZE_BYTES, - .data = - instrumentedAllocatorAllocate(&mem_payload, - HEADER_SIZE_BYTES)}, + UdpardMutablePayload) {.size = HEADER_SIZE_BYTES, + .data = + instrumentedAllocatorAllocate(&mem_payload, + HEADER_SIZE_BYTES)}, mem, &transfer)); TEST_ASSERT_EQUAL(2, mem_session.allocated_fragments); // Not increased. @@ -2312,7 +2312,7 @@ static inline void testPortAcceptFrameA(void) 0, 10000070, makeDatagramPayloadString(&mem_payload, // - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityImmediate, .src_node_id = 10000, .dst_node_id = UDPARD_NODE_ID_UNSET, @@ -2334,7 +2334,7 @@ static inline void testPortAcceptFrameA(void) 0, 10000080, makeDatagramPayloadString(&mem_payload, // - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityImmediate, .src_node_id = 10000, .dst_node_id = UDPARD_NODE_ID_UNSET, @@ -2358,7 +2358,7 @@ static inline void testPortAcceptFrameA(void) 2, 10000090, makeDatagramPayloadString(&mem_payload, // - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityImmediate, .src_node_id = 10001, .dst_node_id = UDPARD_NODE_ID_UNSET, diff --git a/tests/src/test_intrusive_tx.c b/tests/src/test_intrusive_tx.c index bdd57d7..8ab1ad0 100644 --- a/tests/src/test_intrusive_tx.c +++ b/tests/src/test_intrusive_tx.c @@ -58,7 +58,7 @@ static void testTxSerializeHeader(void) HeaderBuffer buffer; TEST_ASSERT_EQUAL_PTR(&buffer.data[0] + HEADER_SIZE_BYTES, txSerializeHeader(buffer.data, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityFast, .src_node_id = 2345, .dst_node_id = 5432, @@ -75,7 +75,7 @@ static void testTxSerializeHeader(void) HeaderBuffer buffer; TEST_ASSERT_EQUAL(&buffer.data[0] + HEADER_SIZE_BYTES, txSerializeHeader(buffer.data, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityLow, .src_node_id = 0xFEDC, .dst_node_id = 0xBA98, @@ -94,43 +94,43 @@ static void testMakeChainEmpty(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityFast, - .src_node_id = 1234, - .dst_node_id = 2345, - .data_specifier = 5432, - .transfer_id = 0xBADC0FFEE0DDF00DULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityFast, + .src_node_id = 1234, + .dst_node_id = 2345, + .data_specifier = 5432, + .transfer_id = 0xBADC0FFEE0DDF00DULL, }; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, 30, 1234567890, meta, - (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C0DU, .udp_port = 0x1234}, - (UdpardPayload){.size = 0, .data = ""}, + (UdpardUDPIPEndpoint) {.ip_address = 0x0A0B0C0DU, .udp_port = 0x1234}, + (UdpardPayload) {.size = 0, .data = ""}, &user_transfer_referent); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + 4, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES + 4, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); TEST_ASSERT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL(NULL, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(1234567890, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(33, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0x0A0B0C0DU, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(0x1234, chain.head->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 4, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, true).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(NULL, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(1234567890, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(33, chain.head->dscp); + TEST_ASSERT_EQUAL(0x0A0B0C0DU, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(0x1234, chain.head->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 4, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, true).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp("\x00\x00\x00\x00", // CRC of the empty transfer. - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, 4)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + 4, chain.head); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); + udpardTxFree(mem, chain.head); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -138,50 +138,49 @@ static void testMakeChainSingleMaxMTU(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPrioritySlow, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPrioritySlow, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, 1234567890, meta, - (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, - (UdpardPayload){.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, + (UdpardUDPIPEndpoint) {.ip_address = 0x0A0B0C00U, .udp_port = 7474}, + (UdpardPayload) {.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, &user_transfer_referent); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); TEST_ASSERT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL(NULL, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(1234567890, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(77, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0x0A0B0C00U, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(7474, chain.head->base.destination.udp_port); + TEST_ASSERT_EQUAL(NULL, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(1234567890, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(77, chain.head->dscp); + TEST_ASSERT_EQUAL(0x0A0B0C00U, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(7474, chain.head->destination.udp_port); TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, - chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, true).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, true).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(DetailOfTheCosmos, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, DetailOfTheCosmosSize)); TEST_ASSERT_EQUAL(0, memcmp(DetailOfTheCosmosCRC, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES + - DetailOfTheCosmosSize, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize, TRANSFER_CRC_SIZE_BYTES)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, chain.head); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); + udpardTxFree(mem, chain.head); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -189,57 +188,59 @@ static void testMakeChainSingleFrameDefaultMTU(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const byte_t payload[UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1] = {0}; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const byte_t payload[UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1] = {0}; { // Ensure UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME bytes fit in a single frame with the default MTU. - const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, - UDPARD_MTU_DEFAULT, - 1234567890, - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL}, - (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, - (UdpardPayload){.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME, .data = payload}, - NULL); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + + const TxChain chain = + txMakeChain(mem, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, + UDPARD_MTU_DEFAULT, + 1234567890, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL}, + (UdpardUDPIPEndpoint) {.ip_address = 0x0A0B0C00U, .udp_port = 7474}, + (UdpardPayload) {.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME, .data = payload}, + NULL); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); TEST_ASSERT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL(NULL, chain.head->base.next_in_transfer); - memFree(mem, - sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + TRANSFER_CRC_SIZE_BYTES, - chain.head); + TEST_ASSERT_EQUAL(NULL, chain.head->next_in_transfer); + udpardTxFree(mem, chain.head); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } { // Increase the payload by 1 byte and ensure it spills over. const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, UDPARD_MTU_DEFAULT, 1234567890, - (TransferMetadata){.priority = UdpardPrioritySlow, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL}, - (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, - (UdpardPayload){.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1, .data = payload}, + (TransferMetadata) {.priority = UdpardPrioritySlow, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL}, + (UdpardUDPIPEndpoint) {.ip_address = 0x0A0B0C00U, .udp_port = 7474}, + (UdpardPayload) {.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1, .data = payload}, NULL); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); - TEST_ASSERT_EQUAL((sizeof(TxItem) + HEADER_SIZE_BYTES) * 2 + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1 + - TRANSFER_CRC_SIZE_BYTES, + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL((sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) * 2 + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + + 1 + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(NULL, chain.tail->next_in_transfer); + udpardTxFree(mem, chain.head); + udpardTxFree(mem, chain.tail); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } } @@ -248,32 +249,36 @@ static void testMakeChainThreeFrames(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityNominal, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const size_t mtu = (EtherealStrengthSize + 4U + 3U) / 3U; // Force payload split into three frames. const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, mtu, 223574680, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, &user_transfer_referent); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(3 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(3, chain.count); - const UdpardTxItem* const first = &chain.head->base; + UdpardTxItem* const first = chain.head; TEST_ASSERT_NOT_EQUAL(NULL, first); - const UdpardTxItem* const second = first->next_in_transfer; + UdpardTxItem* const second = first->next_in_transfer; TEST_ASSERT_NOT_EQUAL(NULL, second); - const UdpardTxItem* const third = second->next_in_transfer; + UdpardTxItem* const third = second->next_in_transfer; TEST_ASSERT_NOT_EQUAL(NULL, third); TEST_ASSERT_EQUAL(NULL, third->next_in_transfer); TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, third); @@ -306,11 +311,11 @@ static void testMakeChainThreeFrames(void) TEST_ASSERT_EQUAL(55, third->dscp); TEST_ASSERT_EQUAL(0xBABADEDAU, third->destination.ip_address); TEST_ASSERT_EQUAL(0xD0ED, third->destination.udp_port); - const size_t third_payload_size = EtherealStrengthSize - 2 * mtu; + const size_t third_payload_size = EtherealStrengthSize - (2 * mtu); TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + third_payload_size + 4U, third->datagram_payload.size); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 2, true).data, third->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, - memcmp(EtherealStrength + 2 * mtu, + memcmp(EtherealStrength + (2 * mtu), (byte_t*) (third->datagram_payload.data) + HEADER_SIZE_BYTES, third_payload_size)); TEST_ASSERT_EQUAL(0, @@ -320,9 +325,9 @@ static void testMakeChainThreeFrames(void) TEST_ASSERT_EQUAL(&user_transfer_referent, third->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, (void*) first); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, (void*) second); - memFree(mem, alloc.allocated_bytes, (void*) third); + udpardTxFree(mem, first); + udpardTxFree(mem, second); + udpardTxFree(mem, third); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -330,71 +335,68 @@ static void testMakeChainCRCSpill1(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityNominal, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const size_t mtu = InterstellarWarSize + 3U; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, mtu, 223574680, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); + TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(NULL, chain.tail->next_in_transfer); // FIRST FRAME -- contains the payload and the first three bytes of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.head->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, false).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.head->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.head->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWar, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, InterstellarWarSize)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES + - InterstellarWarSize, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES + InterstellarWarSize, 3U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); // SECOND FRAME -- contains the last byte of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.tail->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.tail->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.tail->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 1U, chain.tail->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 1, true).data, - chain.tail->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.tail->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.tail->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.tail->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 1U, chain.tail->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, true).data, chain.tail->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC + 3U, - (byte_t*) (chain.tail->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.tail->datagram_payload.data) + HEADER_SIZE_BYTES, 1U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, chain.head); + udpardTxFree(mem, chain.tail); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -402,71 +404,68 @@ static void testMakeChainCRCSpill2(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityNominal, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const size_t mtu = InterstellarWarSize + 2U; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, mtu, 223574680, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); + TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(NULL, chain.tail->next_in_transfer); // FIRST FRAME -- contains the payload and the first two bytes of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.head->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, false).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.head->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.head->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWar, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, InterstellarWarSize)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES + - InterstellarWarSize, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES + InterstellarWarSize, 2U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); // SECOND FRAME -- contains the last two bytes of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.tail->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.tail->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.tail->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 2U, chain.tail->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 1, true).data, - chain.tail->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.tail->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.tail->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.tail->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 2U, chain.tail->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, true).data, chain.tail->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC + 2U, - (byte_t*) (chain.tail->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.tail->datagram_payload.data) + HEADER_SIZE_BYTES, 2U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, chain.head); + udpardTxFree(mem, chain.tail); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -474,71 +473,68 @@ static void testMakeChainCRCSpill3(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityNominal, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const size_t mtu = InterstellarWarSize + 1U; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, mtu, 223574680, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); + TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(NULL, chain.tail->next_in_transfer); // FIRST FRAME -- contains the payload and the first byte of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.head->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, false).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.head->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.head->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWar, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, InterstellarWarSize)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES + - InterstellarWarSize, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES + InterstellarWarSize, 1U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); // SECOND FRAME -- contains the last three bytes of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.tail->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.tail->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.tail->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 3U, chain.tail->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 1, true).data, - chain.tail->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.tail->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.tail->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.tail->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 3U, chain.tail->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, true).data, chain.tail->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC + 1U, - (byte_t*) (chain.tail->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.tail->datagram_payload.data) + HEADER_SIZE_BYTES, 3U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, chain.head); + udpardTxFree(mem, chain.tail); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -546,67 +542,65 @@ static void testMakeChainCRCSpillFull(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - char user_transfer_referent = '\0'; - const TransferMetadata meta = { - .priority = UdpardPriorityNominal, - .src_node_id = 4321, - .dst_node_id = 5432, - .data_specifier = 7766, - .transfer_id = 0x0123456789ABCDEFULL, + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + char user_transfer_referent = '\0'; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, }; const size_t mtu = InterstellarWarSize; const TxChain chain = txMakeChain(mem, - (byte_t[]){11, 22, 33, 44, 55, 66, 77, 88}, + (byte_t[]) {11, 22, 33, 44, 55, 66, 77, 88}, mtu, 223574680, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); - TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); - TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); + TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->next_in_transfer); + TEST_ASSERT_EQUAL(NULL, chain.tail->next_in_transfer); // FIRST FRAME -- contains the payload only. - TEST_ASSERT_EQUAL(223574680, chain.head->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.head->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.head->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + InterstellarWarSize, chain.head->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 0, false).data, - chain.head->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.head->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.head->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.head->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.head->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + mtu, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + InterstellarWarSize, chain.head->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, chain.head->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWar, - (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.head->datagram_payload.data) + HEADER_SIZE_BYTES, InterstellarWarSize)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->user_transfer_reference); // SECOND FRAME -- contains the last byte of the CRC. - TEST_ASSERT_EQUAL(223574680, chain.tail->base.deadline_usec); - TEST_ASSERT_EQUAL(55, chain.tail->base.dscp); - TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->base.destination.ip_address); - TEST_ASSERT_EQUAL(0xD0ED, chain.tail->base.destination.udp_port); - TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 4U, chain.tail->base.datagram_payload.size); - TEST_ASSERT_EQUAL(0, - memcmp(makeHeader(meta, 1, true).data, - chain.tail->base.datagram_payload.data, - HEADER_SIZE_BYTES)); + TEST_ASSERT_EQUAL(223574680, chain.tail->deadline_usec); + TEST_ASSERT_EQUAL(55, chain.tail->dscp); + TEST_ASSERT_EQUAL(0xBABADEDAU, chain.tail->destination.ip_address); + TEST_ASSERT_EQUAL(0xD0ED, chain.tail->destination.udp_port); + TEST_ASSERT_EQUAL(HEADER_SIZE_BYTES + 4U, chain.tail->datagram_payload.size); + TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, true).data, chain.tail->datagram_payload.data, HEADER_SIZE_BYTES)); TEST_ASSERT_EQUAL(0, memcmp(InterstellarWarCRC, - (byte_t*) (chain.tail->base.datagram_payload.data) + HEADER_SIZE_BYTES, + (byte_t*) (chain.tail->datagram_payload.data) + HEADER_SIZE_BYTES, 4U)); - TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); + TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, chain.head); + udpardTxFree(mem, chain.tail); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -614,8 +608,11 @@ static void testPushPeekPopFree(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx = { .local_node_id = &node_id, @@ -638,14 +635,15 @@ static void testPushPeekPopFree(void) txPush(&tx, 1234567890U, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); - TEST_ASSERT_EQUAL(3 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * (sizeof(struct UdpardTxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, + alloc.allocated_bytes); TEST_ASSERT_EQUAL(3, tx.queue_size); - const UdpardTxItem* frame = udpardTxPeek(&tx); + UdpardTxItem* frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_NOT_EQUAL(NULL, frame->next_in_transfer); TEST_ASSERT_EQUAL(1234567890U, frame->deadline_usec); @@ -656,7 +654,7 @@ static void testPushPeekPopFree(void) TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2, tx.queue_size); frame = udpardTxPeek(&tx); @@ -670,7 +668,7 @@ static void testPushPeekPopFree(void) TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); frame = udpardTxPeek(&tx); @@ -693,8 +691,11 @@ static void testPushPrioritization(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx = { .local_node_id = &node_id, @@ -717,12 +718,12 @@ static void testPushPrioritization(void) txPush(&tx, 0, meta_a, - (UdpardUDPIPEndpoint){.ip_address = 0xAAAAAAAA, .udp_port = 0xAAAA}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xAAAAAAAA, .udp_port = 0xAAAA}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3, tx.queue_size); - const UdpardTxItem* frame = udpardTxPeek(&tx); + UdpardTxItem* frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); @@ -730,17 +731,17 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(1, txPush(&tx, 0, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityHigh, .src_node_id = 100, .dst_node_id = UDPARD_NODE_ID_UNSET, .data_specifier = 200, .transfer_id = 100000, }, - (UdpardUDPIPEndpoint){.ip_address = 0xBBBBBBBB, .udp_port = 0xBBBB}, - (UdpardPayload){.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBBBBBBBB, .udp_port = 0xBBBB}, + (UdpardPayload) {.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, NULL)); - TEST_ASSERT_EQUAL(4, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(4, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -750,17 +751,17 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(1, txPush(&tx, 1002, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityLow, .src_node_id = 100, .dst_node_id = UDPARD_NODE_ID_UNSET, .data_specifier = 200, .transfer_id = 10000, }, - (UdpardUDPIPEndpoint){.ip_address = 0xCCCCCCCC, .udp_port = 0xCCCC}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xCCCCCCCC, .udp_port = 0xCCCC}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(5, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(5, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -770,17 +771,17 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(1, txPush(&tx, 1003, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityLow, .src_node_id = 100, .dst_node_id = UDPARD_NODE_ID_UNSET, .data_specifier = 200, .transfer_id = 10001, }, - (UdpardUDPIPEndpoint){.ip_address = 0xDDDDDDDD, .udp_port = 0xDDDD}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xDDDDDDDD, .udp_port = 0xDDDD}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(6, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(6, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -790,17 +791,17 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(1, txPush(&tx, 1003, - (TransferMetadata){ + (TransferMetadata) { .priority = UdpardPriorityFast, .src_node_id = 100, .dst_node_id = UDPARD_NODE_ID_UNSET, .data_specifier = 200, .transfer_id = 1000, }, - (UdpardUDPIPEndpoint){.ip_address = 0xEEEEEEEE, .udp_port = 0xEEEE}, - (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, + (UdpardUDPIPEndpoint) {.ip_address = 0xEEEEEEEE, .udp_port = 0xEEEE}, + (UdpardPayload) {.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(7, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(7 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(7, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -809,14 +810,14 @@ static void testPushPrioritization(void) // Now, unwind the queue and ensure the frames are popped in the right order. // E udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(6, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(6, tx.queue_size); // B frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_EQUAL(0xBBBBBBBB, frame->destination.ip_address); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(5, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(5, tx.queue_size); // A1, three frames. frame = udpardTxPeek(&tx); @@ -824,7 +825,7 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 0, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(4, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(4, tx.queue_size); // A2 frame = udpardTxPeek(&tx); @@ -832,7 +833,7 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 1, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3, tx.queue_size); // A3 frame = udpardTxPeek(&tx); @@ -840,14 +841,14 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 2, true).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2, tx.queue_size); // C frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_EQUAL(0xCCCCCCCC, frame->destination.ip_address); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); // D frame = udpardTxPeek(&tx); @@ -864,8 +865,11 @@ static void testPushCapacityLimit(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx = { .local_node_id = &node_id, @@ -887,8 +891,8 @@ static void testPushCapacityLimit(void) txPush(&tx, 1234567890U, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc.allocated_bytes); @@ -899,8 +903,11 @@ static void testPushOOM(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx = { .local_node_id = &node_id, @@ -923,8 +930,48 @@ static void testPushOOM(void) txPush(&tx, 1234567890U, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, + NULL)); + TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(0, alloc.allocated_bytes); + TEST_ASSERT_EQUAL(0, tx.queue_size); +} + +static void testPushPayloadOOM(void) +{ + InstrumentedAllocator alloc; + instrumentedAllocatorNew(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; + // + UdpardTx tx = { + .local_node_id = &node_id, + .queue_capacity = 10000U, + .mtu = EtherealStrengthSize + HEADER_CRC_SIZE_BYTES, + .dscp_value_per_priority = {0, 1, 2, 3, 4, 5, 6, 7}, + .memory = mem, + .queue_size = 0, + .root = NULL, + }; + const TransferMetadata meta = { + .priority = UdpardPriorityNominal, + .src_node_id = 4321, + .dst_node_id = 5432, + .data_specifier = 7766, + .transfer_id = 0x0123456789ABCDEFULL, + }; + // There is memory of the item, but 1 byte short for payload. + alloc.limit_bytes = sizeof(UdpardTxItem) + (HEADER_SIZE_BYTES + EtherealStrengthSize + HEADER_CRC_SIZE_BYTES - 1); + TEST_ASSERT_EQUAL(-UDPARD_ERROR_MEMORY, + txPush(&tx, + 1234567890U, + meta, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc.allocated_bytes); @@ -935,8 +982,11 @@ static void testPushAnonymousMultiFrame(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 0xFFFFU; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 0xFFFFU; // UdpardTx tx = { .local_node_id = &node_id, @@ -958,8 +1008,8 @@ static void testPushAnonymousMultiFrame(void) txPush(&tx, 1234567890U, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc.allocated_bytes); @@ -970,8 +1020,11 @@ static void testPushAnonymousService(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 0xFFFFU; + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 0xFFFFU; // UdpardTx tx = { .local_node_id = &node_id, @@ -993,8 +1046,8 @@ static void testPushAnonymousService(void) txPush(&tx, 1234567890U, meta, - (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, - (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, + (UdpardUDPIPEndpoint) {.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, + (UdpardPayload) {.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); TEST_ASSERT_EQUAL(0, alloc.allocated_bytes); @@ -1021,6 +1074,7 @@ int main(void) RUN_TEST(testPushPrioritization); RUN_TEST(testPushCapacityLimit); RUN_TEST(testPushOOM); + RUN_TEST(testPushPayloadOOM); RUN_TEST(testPushAnonymousMultiFrame); RUN_TEST(testPushAnonymousService); return UNITY_END(); diff --git a/tests/src/test_tx.cpp b/tests/src/test_tx.cpp index 9579744..5f5a025 100644 --- a/tests/src/test_tx.cpp +++ b/tests/src/test_tx.cpp @@ -29,49 +29,55 @@ void testInit() std::monostate user_referent; const UdpardNodeID node_id = 0; { - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(nullptr, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, nullptr, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = nullptr, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = nullptr, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(0, udpardTxInit(&tx, &node_id, 0, memory)); - TEST_ASSERT_EQUAL(&user_referent, tx.memory.user_reference); + TEST_ASSERT_EQUAL(&user_referent, tx.memory.fragment.user_reference); + TEST_ASSERT_EQUAL(&user_referent, tx.memory.payload.user_reference); TEST_ASSERT_EQUAL(UDPARD_MTU_DEFAULT, tx.mtu); } } @@ -80,8 +86,11 @@ void testPublish() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx{ .local_node_id = &node_id, @@ -102,9 +111,9 @@ void testPublish() transfer_id++, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); - const auto* frame = udpardTxPeek(&tx); + auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n"; TEST_ASSERT_NOT_EQUAL(nullptr, frame); TEST_ASSERT_EQUAL(nullptr, frame->next_in_transfer); @@ -212,8 +221,11 @@ void testRequest() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx{ .local_node_id = &node_id, @@ -235,9 +247,9 @@ void testRequest() transfer_id++, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); - const auto* frame = udpardTxPeek(&tx); + auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n"; TEST_ASSERT_NOT_EQUAL(nullptr, frame); TEST_ASSERT_EQUAL(nullptr, frame->next_in_transfer); @@ -362,8 +374,11 @@ void testRespond() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); - const UdpardNodeID node_id = 1234; + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; + const UdpardNodeID node_id = 1234; // UdpardTx tx{ .local_node_id = &node_id, @@ -384,9 +399,9 @@ void testRespond() 9876543210, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); - const auto* frame = udpardTxPeek(&tx); + auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n"; TEST_ASSERT_NOT_EQUAL(nullptr, frame); TEST_ASSERT_EQUAL(nullptr, frame->next_in_transfer); diff --git a/tools/run_sonar.sh b/tools/run_sonar.sh index c0440d1..0fcba11 100755 --- a/tools/run_sonar.sh +++ b/tools/run_sonar.sh @@ -69,7 +69,7 @@ sonar-scanner \ --define sonar.projectKey=libudpard \ --define sonar.sources=libudpard \ --define sonar.exclusions=libudpard/_udpard_cavl.h \ ---define sonar.cfamily.build-wrapper-output="$BUILD_DIR" \ +--define sonar.cfamily.compile-commands="$BUILD_DIR/compile_commands.json" \ --define sonar.cfamily.llvm-cov.reportPath="$BUILD_DIR/coverage.txt" \ --define sonar.cfamily.threads="$(nproc)" \ || die