diff options
Diffstat (limited to 'libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h')
-rw-r--r-- | libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h new file mode 100644 index 00000000..81866701 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h @@ -0,0 +1,441 @@ +/* + * 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. + */ + +/** + * @file ccnxCodec_TlvUtilities.h + * @brief Utility functions common to all the codecs + * + * <#Detailed Description#> + * + */ +#ifndef TransportRTA_ccnxCodec_TlvUtilities_h +#define TransportRTA_ccnxCodec_TlvUtilities_h + +#include <stdbool.h> +#include <stdint.h> +#include <ccnx/common/internal/ccnx_TlvDictionary.h> +#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h> +#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h> + +/** + * Decodes a list of TLV entries + * + * The decoder should point to the first byte of a "type". This function will iterate over all the TLVs + * and call the user function 'typeDecoder' for each type-length. + * + * It is the responsibility of typeDecoder to advance the decoder by 'length' bytes. It should return false + * if it does not consume exactly 'length' bytes. + * + * The function will proceed until it can no longer parse a TLV header (4 bytes). If the function consumes all + * the bytes in the decoder without error, it will return true. If it encounters an error from 'typeDecoder' it + * will return false at that point. If there is an underflow (i.e. 1, 2, or 3 bytes) left in the decoder at the end + * it will return false. + * + * @param [in] decoder The TLV decoder that should point to the start of the TLV list + * @param [in] packetDictionary The dictionary to use to store packet fields + * @param [in] typeDecoder the user-supplied function to call for each TLV found in the container + * + * @return true There were no errors returned by 'typeDecoder' and we consumed the entire decoder buffer + * @return false There was an error or we did not consume the entire decoder buffer. + * + * Example: + * @code + * { + * static bool + * testTypeDecoder(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) + * { + * switch (type) { + * case 0x000C: // fallthrough + * case 0x000D: + * ccnxCodecTlvDecoder_Advance(decoder, length); + * return true; + * default: + * return false; + * } + * } + * + * void foo(void) + * { + * // A list of 2 TLV containers (types 0x000C and 0x000D) + * uint8_t metadataContainer[] = { + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * }; + * + * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) ); + * + * // now decode that snippit + * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10); + * + * bool success = ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, testTypeDecoder); + * + * ccnxTlvDictionary_Release(&dictionary); + * ccnxCodecTlvDecoder_Destroy(&decoder); + * parcBuffer_Release(&buffer); + * + * assertTrue(success, "The TLV types were known to us"); + * } + * @endcode + */ +bool ccnxCodecTlvUtilities_DecodeContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, bool (*typeDecoder)(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)); + +/** + * Creates an inner decoder of for decoding a subcontainer + * + * The decoder should point at the first byte of the "value", which is known to be a subcontainer listing other + * TLVs. This function will create an inner decoder and then call 'ccnxCodecTlvUtilities_DecodeContainer' with it to + * decode the inner TLVs. + * + * @param [in] decoder The decoder that points to the fist byte of a list of TLVs. + * @param [in] packetDictionary Where to put the results + * @param [in] key NOT USED + * @param [in] length The length of the subcontainer. The inner decoder will end after this may bytes. + * @param [in] subcontainerDecoder The function to pass to 'ccnxCodecTlvUtilities_DecodeContainer' for the inner decoder + * + * @return true There were no errors and consumed 'length' bytes + * @return false An error or did not consume 'length' bytes + * + * Example: + * @code + * { + * // The KeyLocator field is known to be a subcontainer containing its own TLV fields. When we encounter that + * // TLV type, we parse the 'value' of it as a subcontainer + * // + * static bool + * rtaTlvSchemaV0NameAuth_DecodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) + * { + * bool success = false; + * switch (type) { + * case CCNxCodecSchemaV0_NameAuthKeys_KeyLocator: + * success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, rtaTlvSchemaV0KeyLocator_Decode); + * break; + * + * case CCNxCodecSchemaV0_NameAuthKeys_CryptoSuite: + * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_CRYPTO_SUITE); + * break; + * + * case CCNxCodecSchemaV0_NameAuthKeys_KeyId: + * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYID); + * break; + * + * default: + * // if we do not know the TLV type, put it in this container's unknown list + * success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectLists_NAMEAUTH_LIST); + * break; + * } + * return success; + * } + * @endcode + */ +bool +ccnxCodecTlvUtilities_DecodeSubcontainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t key, uint16_t length, + bool (*subcontainerDecoder)(CCNxCodecTlvDecoder *, CCNxTlvDictionary *)); + +/** + * Decodes 'length' bytes from the decoder and puts it in the dictionary + * + * Reads the next 'length' bytes from the decoder and wraps it in a PARCBuffer. The buffer is saved in the packetDictionary + * under the key 'arrayKey'. + * + * It is an error if there are not 'length' bytes remaining in the decoder. + * + * @param [in] decoder The input to read + * @param [in] packetDictionary The output dictionary to save the buffer in + * @param [in] key The TLV key of the value being read (NOT USED) + * @param [in] length The byte length to read + * @param [in] dictionaryKey The key to use in the packetDictionary + * + * @return true 'length' bytes were read and saved in the packetDictionary + * @return false An error + * + * Example: + * @code + * { + * // A list of 2 TLV containers (types 0x000C and 0x000D) + * uint8_t metadataContainer[] = { + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * }; + * + * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) ); + * + * // now decode that snippit + * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10); + * + * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder); + * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder); + * + * // The buffer will contain the one byte 0x04. + * bool success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_OBJ_TYPE); + * + * ccnxTlvDictionary_Release(&dictionary); + * ccnxCodecTlvDecoder_Destroy(&decoder); + * parcBuffer_Release(&buffer); + * + * assertTrue(success, "There was an unknown TLV at position %zu", ccnxCodecTlvDecoder_Position(decoder)); + * } + * @endcode + */ +bool +ccnxCodecTlvUtilities_PutAsBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey); + +/** + * Decodes a `PARCCryptoHash` value of 'length' bytes from the decoder and puts it in the dictionary. + * + * It is an error if there are not 'length' bytes remaining in the decoder. + * + * @param [in] decoder The input to read + * @param [in] packetDictionary The output dictionary to save the buffer in + * @param [in] key The TLV key of the value being read (NOT USED) + * @param [in] length The byte length to read + * @param [in] dictionaryKey The key to use in the packetDictionary + * + * @return true 'length' bytes were read and saved in the packetDictionary + * @return false An error + * + * Example: + * @code + * { + * // A list of 2 TLV containers (types 0x000C and 0x000D) + * uint8_t hashContainer[] = { + * 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length = 0x20 + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + * }; + * + * PARCBuffer *buffer = parcBuffer_Wrap(hashContainer, sizeof(hashContainer), 0, sizeof(hashContainer) ); + * + * // now decode that snippit + * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10); + * + * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder); + * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder); + * + * bool success = ccnxCodecTlvUtilities_PutAsHash(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); + * + * ccnxTlvDictionary_Release(&dictionary); + * ccnxCodecTlvDecoder_Destroy(&decoder); + * parcBuffer_Release(&buffer); + * } + * @endcode + */ +bool +ccnxCodecTlvUtilities_PutAsHash(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey); + +/** + * Decodes the value as a VarInt and saves it as an Integer in the Dictionary + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool +ccnxCodecTlvUtilities_PutAsInteger(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey); + + +/** + * Decodes 'length' bytes from the decoder and puts it in the dictionary as a CCNxName + * + * Reads the next 'length' bytes from the decoder and wraps it in a CCNxName. The name is saved in the packetDictionary + * under the key 'arrayKey'. + * + * It is an error if there are not 'length' bytes remaining in the decoder. + * + * @param [in] decoder The input to read + * @param [in] packetDictionary The output dictionary to save the name in + * @param [in] key The TLV key of the value being read (NOT USED) + * @param [in] length The byte length to read + * @param [in] dictionaryKey The key to use in the packetDictionary + * + * @return true 'length' bytes were read and saved in the packetDictionary + * @return false An error + * + * Example: + * @code + * { + * // A list of 2 TLV containers (types 0x000C and 0x000D) + * uint8_t metadataContainer[] = { + * 0x00, 0x00, 0x00, 9, // type = name, length = 9 + * 0x00, 0x02, 0x00, 5, // type = binary, length = 5 + * 'h', 'e', 'l', 'l', // "hello" + * 'o', + * }; + * + * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) ); + * + * // now decode that snippit + * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10); + * + * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder); + * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder); + * + * // Saves "lci:/hello" + * bool success = ccnxCodecTlvUtilities_PutAsName(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_NAME); + * + * ccnxTlvDictionary_Release(&dictionary); + * ccnxCodecTlvDecoder_Destroy(&decoder); + * parcBuffer_Release(&buffer); + * + * assertTrue(success, "The Name failed to decode or some other error"); + * } + * @endcode + */ +bool +ccnxCodecTlvUtilities_PutAsName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey); + +/** + * Reads 'length' bytes from the decoder and appends a PARCBuffer to a list in packetDictionary + * + * Saves a buffer as part of a List in the packet dictionary. This is primarily used for unknown TLV types that + * do not have a specific decoder. + * + * @param [in] decoder The decoder to read + * @param [in] packetDictionary The dictionary to append the buffer in + * @param [in] type The TLV type of the buffer (saved as part of the list entry) + * @param [in] length The length to wrap in the buffer + * @param [in] listKey The list key in packetDictionary + * + * @return true Success + * @return false Failure or error + * + * Example: + * @code + * { + * // If we exhaust all the known keys in the Name Authenticator, the default case will save the TLV in + * // the container's list in the packet dictionary. + * // + * static bool + * rtaTlvSchemaV0NameAuth_DecodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) + * { + * bool success = false; + * switch (type) { + * case CCNxCodecSchemaV0_NameAuthKeys_KeyLocator: + * success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, rtaTlvSchemaV0KeyLocator_Decode); + * break; + * + * case CCNxCodecSchemaV0_NameAuthKeys_CryptoSuite: + * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_CRYPTO_SUITE); + * break; + * + * case CCNxCodecSchemaV0_NameAuthKeys_KeyId: + * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYID); + * break; + * + * default: + * // if we do not know the TLV type, put it in this container's unknown list + * success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectLists_NAMEAUTH_LIST); + * break; + * } + * return success; + * } + * @endcode + */ +bool +ccnxCodecTlvUtilities_PutAsListBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int listKey); + +/** + * Encodes a nested TLV container (the opposite of ccnxCodecTlvUtilities_DecodeSubcontainer) + * + * Appends a TLV header (4 bytes) to the encoder using 'nestedType' as the TLV type. It then calls 'nestedEncoderFunction' to + * encode the 'value' of the container. If 'nestedEncoderFunction' returns positive bytes it will go back and fill in the proper TLV length. + * If 'nestedEncoderFunction' returns 0 or negative bytes, it rewinds the encoder to the original position before appending the TLV header. + * + * @param [in] outerEncoder The encoder to append to + * @param [in] packetDictionary The dictionary to read from + * @param [in] nestedType the TLV type to use for the nested value + * @param [in] nestedEncoderFunction The function to call to write the inner value + * + * @return non-negative The total number of bytes appended to 'outerEncoder' + * @return -1 An error + * + * Example: + * @code + * { + * // If the dictionary contains a KeyName Name, then encode the KeyName continer using 'rtaTlvSchemaV0KeyName_Encode'. Use + * // the value 'CCNxCodecSchemaV0_KeyLocatorKeys_KeyName' as the TLV type for the subcontainer. + * // + * if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYNAME_NAME)) { + * keynameLength = ccnxCodecTlvUtilities_NestedEncode(keyLocatorEncoder, packetDictionary, CCNxCodecSchemaV0_KeyLocatorKeys_KeyName, rtaTlvSchemaV0KeyName_Encode); + * } + * } + * @endcode + */ +ssize_t +ccnxCodecTlvUtilities_NestedEncode(CCNxCodecTlvEncoder *outerEncoder, CCNxTlvDictionary *packetDictionary, uint32_t nestedType, + ssize_t (*nestedEncoderFunction)(CCNxCodecTlvEncoder *innerEncoder, CCNxTlvDictionary *packetDictionary)); + +/** + * Reads the list 'listKey' from the dictionary and encodes them all as TLV entries + * + * <#Paragraphs Of Explanation#> + * + * @param [in] encoder The encoder to append to + * @param [in] packetDictionary The dictionary to read from + * @param [in] listKey The list key to read from packetDictionary + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t +ccnxCodecTlvUtilities_EncodeCustomList(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary, int listKey); + + +/** + * Parses the input buffer as a VarInt + * + * Parses the bytes of the input buffer as a network byte order variable length integer. + * Between 1 and 'length' bytes will be parses, where 'length' must be from 1 to 8. + * The buffer will be advanced as the bytes are read. + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * { + * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 ); + * uint64_t value; + * ccnxCodecTlvUtilities_GetVarInt(buffer, 3, &value); + * // value = 0x0000000000102300 + * } + * @endcode + */ +bool ccnxCodecTlvUtilities_GetVarInt(PARCBuffer *input, size_t length, uint64_t *output); + +#endif // TransportRTA_ccnxCodec_TlvUtilities_h |