diff options
Diffstat (limited to 'libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c')
-rw-r--r-- | libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c new file mode 100644 index 00000000..f925dd28 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> +#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h> + +#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h> + + +#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h> + +#include <ccnx/common/codec/test/testrig_Compare.c> + +/** + * Finds a row in the truthtable where bodyManifest is TRUE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +/** + * Finds a row in the truthtable where bodyManifest is FALSE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +typedef struct test_data { + // the memory region extracted from a Truth Table entry + PARCBuffer *memoryRegion; + + CCNxCodecTlvEncoder *encoder; + CCNxTlvDictionary *dictionary; + + uint8_t *packet; + size_t packetLength; + TruthTableEntry *truthTable; + + // If the user creates one of these, we'll destroy it. + PARCSigner *signer; +} TestData; + +static SchemaV1ManifestContentObjectBody manifestContentObjectContainerArray[] = { + V1_MANIFEST_OBJ_CONTENTOBJECT, + V1_MANIFEST_OBJ_NAMEAUTH, + V1_MANIFEST_OBJ_ValidationPayload, + V1_MANIFEST_OBJ_KEYNAME, + V1_MANIFEST_OBJ_METADATA, + V1_MANIFEST_OBJ_ValidationAlg, + V1_MANIFEST_OBJ_BODYEND +}; + +static bool +isContentObjectContainer(SchemaV1ManifestContentObjectBody value) +{ + for (int i = 0; manifestContentObjectContainerArray[i] != V1_MANIFEST_OBJ_BODYEND; i++) { + if (value == manifestContentObjectContainerArray[i]) { + return true; + } + } + return false; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_MessageFastArray +translateTestDataManifestToSchemaKey(SchemaV1ManifestContentObjectBody oldKey) +{ + switch (oldKey) { + case V1_MANIFEST_INT_NAME: + // fallthrough + case V1_MANIFEST_OBJ_NAME: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME; + + case V1_MANIFEST_OBJ_PAYLOAD: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_KEYID: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID; + + case V1_MANIFEST_OBJ_CRYPTO_SUITE: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE; + + case V1_MANIFEST_OBJ_KEY: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY; + + case V1_MANIFEST_OBJ_CERT: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT; + + case V1_MANIFEST_OBJ_KEYNAME_NAME: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME; + + case V1_MANIFEST_OBJ_KEYNAME_OBJHASH: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH; + + case V1_MANIFEST_OBJ_OBJ_TYPE: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE; + + case V1_MANIFEST_OBJ_SIGBITS: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_SigningTime: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME; + + case V1_MANIFEST_OBJ_ENDSEGMENT: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT; + + case V1_MANIFEST_INT_KEYID: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION; + + case V1_MANIFEST_INT_OBJHASH: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + return -1; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_HeadersFastArray +translateOldOptionalHeadersManifestToNewKey(CCNxTlvDictionary *packetDictionary, int oldKey) +{ + if (ccnxTlvDictionary_IsInterest(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_INT_LIFETIME: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime; + + case V1_MANIFEST_INT_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_OBJ_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } + return -1; +} + +static void +addBuffer(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); +} + +/** + * The extent should be treated like a CCNxName, so decode it and add it as a CCNxName. + */ +static void +addName(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + // we need to backup 4 bytes to the the TLV container + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start - 4, item_end); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(itemBuffer); + CCNxName *name = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name); + ccnxCodecTlvDecoder_Destroy(&decoder); + + ccnxTlvDictionary_PutName(packetDictionary, translatedKey, name); + ccnxName_Release(&name); + parcBuffer_Release(&itemBuffer); +} + + +/** + * Called on the body of a content object, does not include the fixed header or optional headers + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildContentObjectDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_ContentObject(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + // Is it a container or a nested dictionary? This check only applies to a ContentObject + if (!isContentObjectContainer(data->truthTable[i].indexOrKey)) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_OBJ_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } + } +} + +static void +buildInterestDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_Interest(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID && data->truthTable[i].bodyManifest; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_INT_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } +} + +/** + * Make a dictionary entry for everything inside the selected extent, not including it + * + * Use the truth table and for each listed item whose extent is within the given extent, + * add a dictionary entry + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildMessageDictionary(TestData *data, CCNxTlvDictionary *dictionary, TlvExtent extent) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + buildInterestDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + buildContentObjectDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +static void +buildSetDictionaryType(TestData *data, CCNxTlvDictionary *dictionary) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +/** + * Builds a packet dictionary with OptionalHeaders and Message + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildPacketDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + buildSetDictionaryType(data, packetDictionary); + + size_t start = extent.offset; + size_t end = start + extent.length; + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + if (data->truthTable[i].bodyManifest == false) { + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + uint32_t translatedKey = translateOldOptionalHeadersManifestToNewKey(packetDictionary, data->truthTable[i].indexOrKey); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); + } else { + buildMessageDictionary(data, packetDictionary, data->truthTable[i].extent); + } + + // advance start to skip over whatever we just included + start = item_end; + } + } +} + +/** + * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set + * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and + * use it's extent as the bounds for the wrapped packet. + * + * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet + * memory and it will have and offset of 32 and a limit of 12. + */ +TestData * +commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey); + + data->memoryRegion = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length); + data->encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(data->encoder); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildMessageDictionary(data, data->dictionary, extent); + return data; +} + +/** + * Wraps a packet like commonSetup, but will do the whole packet including headers not just + * the message body. This is used by the PacketEncoder tests. + */ +TestData * +testrigencoder_CommonSetupWholePacket(uint8_t *packet, size_t length, TruthTableEntry *truthTable) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->memoryRegion = parcBuffer_Wrap(packet, length, 0, length); + data->encoder = ccnxCodecTlvEncoder_Create(); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildPacketDictionary(data, data->dictionary, (TlvExtent) { 0, length }); + + return data; +} + +void +testrigencoder_CommonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvEncoder_Destroy(&data->encoder); + parcBuffer_Release(&data->memoryRegion); + + if (data->signer) { + parcSigner_Release(&data->signer); + } + + parcMemory_Deallocate((void **) &data); +} + +void +testDisplayIoVec(CCNxCodecEncodingBufferIOVec *vec) +{ + printf("Display iovec %p with %d elements\n", (void *) vec, vec->iovcnt); + size_t totalLength = 0; + for (int i = 0; i < vec->iovcnt; i++) { + totalLength += vec->iov[i].iov_len; + printf(" %3d: base %p length %4zu total length %4zu\n", i, (void *) vec->iov[i].iov_base, vec->iov[i].iov_len, totalLength); + } + printf("done\n\n"); +} + +void +testExecute(TestData *data, ssize_t (*encoderFunction)(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *dictionary)) +{ + encoderFunction(data->encoder, data->dictionary); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} |