LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType) { uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, 0x00, 0x02, 0x00, 0x20, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); bool result = _decodeType(decoder, dict, type, length); assertTrue(result, "Expected the manifest type to be correctly decoded at the top level"); ccnxManifest_Release(&dict); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
/** * Decodes the CCNx message inside a TLV packet * * Creates an inner decoder that slices the decode buffer then passes that and our * message dictionary to the appropriate inner decoder. * * @param [in] data The packet decoder state * * @return true successful decode * @return false A decoding error * * Example: * @code * <#example#> * @endcode */ static bool _decodeMessage(_CCNxCodecSchemaV1Data *data) { bool success = false; if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) { // what kind of message are we looking at? // Note that this is based on the TLV container, not the fixed head PacketType uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder); uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder); // ensure its a proper tlv type switch (tlv_type) { case CCNxCodecSchemaV1Types_MessageType_Interest: // fallthrough case CCNxCodecSchemaV1Types_MessageType_ContentObject: // fallthrough case CCNxCodecSchemaV1Types_MessageType_Control: // fallthrough break; default: return false; } // cross check with the fixed header value // ccnxCodecSchemaV1FixedHeaderDecoder_Decode ensures that PacketLength is not less than HeaderLength size_t messageLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->packetDictionary) - ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->packetDictionary); if (tlv_length <= messageLength && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { // This decode is for the "value" of the message, it does not include the wrapper CCNxCodecTlvDecoder *messageDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Control) { // the CPI messages are not a proper "message" in that there's no inner TLV, its just data success = _decodeCPI(messageDecoder, data->packetDictionary); } else { success = ccnxCodecSchemaV1MessageDecoder_Decode(messageDecoder, data->packetDictionary); } ccnxCodecTlvDecoder_Destroy(&messageDecoder); } else { // raise an error CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } } return success; }
bool ccnxCodecTlvUtilities_DecodeContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, bool (*typeDecoder)(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)) { while (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { bool success = typeDecoder(decoder, packetDictionary, type, length); if (!success) { return false; } } else { // overflow! The TLV length goes beyond the end of the container return false; } } // Make sure we used up the whole buffer. If we're at the end, // then it was a successful decode, otherwise something is wrong. return ccnxCodecTlvDecoder_IsEmpty(decoder); }
static bool _decodeValidationPayload(_CCNxCodecSchemaV1Data *data) { bool success = false; if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) { // what kind of message are we looking at? // Note that this is based on the TLV container, not the fixed head PacketType uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder); uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder); if (tlv_type == CCNxCodecSchemaV1Types_MessageType_ValidationPayload && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, data->packetDictionary); ccnxCodecTlvDecoder_Destroy(&decoder); } } return success; }
LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup) { uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, 0x00, 0x02, 0x00, 0x20, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); ccnxCodecTlvDecoder_GetType(decoder); // swallow type uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); bool result = _decodeHashGroup(decoder, dict, group, length); assertTrue(result, "Expected hash group to be decoded correctly."); PARCBuffer *expectedPointer = parcBuffer_AllocateCString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0); const PARCBuffer *actualPointer = ccnxManifestHashGroupPointer_GetDigest(pointer); assertTrue(parcBuffer_Equals(expectedPointer, actualPointer), "Expected decoded pointer to equal %s, got %s", parcBuffer_ToHexString(expectedPointer), parcBuffer_ToHexString(actualPointer)); parcBuffer_Release(&expectedPointer); ccnxManifestHashGroup_Release(&group); ccnxManifest_Release(&dict); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }
static bool _decodeValidationAlg(_CCNxCodecSchemaV1Data *data) { bool success = false; if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) { // what kind of message are we looking at? // Note that this is based on the TLV container, not the fixed head PacketType uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder); uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder); if (tlv_type == CCNxCodecSchemaV1Types_MessageType_ValidationAlg && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, data->packetDictionary); ccnxCodecTlvDecoder_Destroy(&decoder); } else { // raise and error if (!ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { // tlv_length goes beyond the decoder CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } else { // not CCNxCodecSchemaV1Types_MessageType_ValidationAlg CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } } } return success; }
LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata) { // Re-build the expected metadata from the manifest CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); PARCBuffer *digest = parcBuffer_Allocate(16); for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { parcBuffer_PutUint8(digest, 0); } parcBuffer_Flip(digest); size_t entrySize = 1; size_t dataSize = 2; size_t blockSize = 3; size_t treeHeight = 4; // Compute the expected size of this metadata group. size_t metadataSize = 4 * (4 + 8) + 4 + parcBuffer_Limit(digest) + 4 + strlen("ccnx:/locator"); // See test_ccnxCodecSchemaV1_ManifestEncoder.c for the packet construction details. uint8_t rawMetadata[89] = { 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, 0x00, metadataSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, 0x00, strlen("ccnx:/locator"), 'c', 'c', 'n', 'x', ':', '/', 'l', 'o', 'c', 'a', 't', 'o', 'r', 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, dataSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, blockSize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, entrySize, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, treeHeight, 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, 0x00, parcBuffer_Remaining(digest), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawMetadata, sizeof(rawMetadata))); // Create the encoder and swallow the top level container CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); ccnxCodecTlvDecoder_GetType(decoder); // swallow type uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); // Decode the metadata CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); bool result = _decodeHashGroupMetadata(decoder, group, length); assertTrue(result, "Expected hash group metadata to be decoded correctly."); const CCNxName *actualLocator = ccnxManifestHashGroup_GetLocator(group); size_t actualEntrySize = ccnxManifestHashGroup_GetEntrySize(group); size_t actualDataSize = ccnxManifestHashGroup_GetDataSize(group); size_t actualBlockSize = ccnxManifestHashGroup_GetBlockSize(group); size_t actualTreeHeight = ccnxManifestHashGroup_GetTreeHeight(group); const PARCBuffer *actualDigest = ccnxManifestHashGroup_GetOverallDataDigest(group); assertTrue(ccnxName_Equals(groupLocator, actualLocator), "Expected decoded locator to equal %s, got %s", ccnxName_ToString(groupLocator), ccnxName_ToString(actualLocator)); assertTrue(entrySize == actualEntrySize, "Expected %zu entry size, got %zu", entrySize, actualEntrySize); assertTrue(dataSize == actualDataSize, "Expected %zu data size, got %zu", dataSize, actualDataSize); assertTrue(blockSize == actualBlockSize, "Expected %zu block size, got %zu", blockSize, actualBlockSize); assertTrue(treeHeight == actualTreeHeight, "Expected %zu tree height, got %zu", treeHeight, actualTreeHeight); assertTrue(parcBuffer_Equals(digest, actualDigest), "Expected %s digest, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actualDigest)); parcBuffer_Release(&digest); ccnxName_Release(&groupLocator); ccnxManifestHashGroup_Release(&group); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&wireFormat); }