aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-common/ccnx/common/codec
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar+fdio@cisco.com>2017-02-23 20:44:26 +0100
committerLuca Muscariello <lumuscar+fdio@cisco.com>2017-02-23 19:51:14 +0000
commitd18ae43123fcd7604d1c36a1ec8450dbe6071824 (patch)
tree2d49fc3aabd0f2607251c854565648d47b56b2e9 /libccnx-common/ccnx/common/codec
parent9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff)
Initial commit: ccnxlibs.
Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0 Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'libccnx-common/ccnx/common/codec')
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c559
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h300
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_Error.c173
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_Error.h190
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h55
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c809
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h833
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c320
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h677
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c382
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h755
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c190
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h135
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c173
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h441
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c137
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h85
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h51
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c210
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h165
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c64
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c149
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h74
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c165
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h76
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c187
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h52
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c166
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h31
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c140
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h57
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c340
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h47
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c85
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h83
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c59
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h64
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c125
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h144
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c187
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h46
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c289
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h91
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c353
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h85
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c68
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h250
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h211
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c176
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h74
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c253
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h79
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore19
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt29
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c154
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c350
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c174
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c235
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c450
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c267
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c306
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c320
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c644
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c139
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c149
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c321
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c205
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c684
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c1054
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c118
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c450
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c565
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c472
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c516
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt27
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h54
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h114
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h181
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h65
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h55
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h57
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h78
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h102
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h57
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h75
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h76
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h102
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h68
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h34
-rw-r--r--libccnx-common/ccnx/common/codec/test/.gitignore7
-rw-r--r--libccnx-common/ccnx/common/codec/test/CMakeLists.txt24
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c343
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c139
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c952
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c808
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c874
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c447
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c496
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_random_bytesbin0 -> 512 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_random_bytes.sigbin0 -> 128 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_rsa.p12bin0 -> 1598 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_rsa_key.pem15
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/testrig_Compare.c90
-rw-r--r--libccnx-common/ccnx/common/codec/testdata/testdata_common.h111
-rwxr-xr-xlibccnx-common/ccnx/common/codec/testdata/tlv_Schema.h29
111 files changed, 24383 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c
new file mode 100644
index 00000000..2fdab85f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c
@@ -0,0 +1,559 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h>
+
+struct ccnx_tlv_encoding_buffer_linked_array;
+typedef struct ccnx_tlv_encoding_buffer_linked_array _CCNxCodecEncodingBufferLinkedArray;
+
+typedef struct array_entry {
+ struct iovec vec;
+ PARCBuffer *buffer;
+} _ArrayEntry;
+
+/**
+ * @typedef CCNxCodecEncodingBufferLinkedArray
+ * @abstract A chain of arrays of PARCBuffers
+ * @constant next The next EncodingBuffer in the chain
+ * @constant prev The previous EncodingBuffer in the chain
+ * @constant cacapcity The array capacity of bufferArray
+ * @constant count The number of items in this EncodingBuffer
+ * @constant bytes The bytes in this EncodingBuffer
+ * @constant bufferArray An array of (PARCBuffer *)
+ * @discussion If 'next' is NULL, then new elements are appendig to bufferArray. If 'next' is
+ * not null, then calls to Append will go to the bufferArray at the tail of the linked list.
+ */
+struct ccnx_tlv_encoding_buffer_linked_array {
+ // we can chain these encoding buffers together to make
+ // one long linear list
+ _CCNxCodecEncodingBufferLinkedArray *next;
+ _CCNxCodecEncodingBufferLinkedArray *prev;
+
+ // the number of elements allocated the array
+ uint32_t capacity;
+
+ // The total number of elements in this bufferArray
+ uint32_t count;
+
+ // The total bytes of this bufferArray
+ size_t bytes;
+
+ // each encoding buffer is an array of _ArrayEntry structures containing
+ // a PARCBuffer reference and a vector referencing the PARCBuffer contents.
+ _ArrayEntry *array;
+};
+
+/**
+ * @typedef CCNxCodecEncodingBuffer
+ * @abstract A chain of arrays of PARCBuffers
+ * @constant next The next EncodingBuffer in the chain
+ * @constant prev The previous EncodingBuffer in the chain
+ * @constant cacapcity The array capacity of bufferArray
+ * @constant totalCount The total number of items in this EncodingBuffer and all subsequent
+ * @constant totalBytes The total number of bytes in this EncodingBuffer and all subsequent
+ * @constant bufferArray An array of (PARCBuffer *)
+ * @discussion If 'next' is NULL, then new elements are appendig to bufferArray. If 'next' is
+ * not null, then calls to Append will go to the bufferArray at the tail of the linked list.
+ */
+struct ccnx_codec_encoding_buffer {
+ _CCNxCodecEncodingBufferLinkedArray *head;
+ _CCNxCodecEncodingBufferLinkedArray *tail;
+
+ // The total number of elements in all LinkedArrays
+ uint32_t totalCount;
+
+ // The total bytes in all LinkedArrays
+ size_t totalBytes;
+};
+
+static void _ccnxCodecEncodingBufferEntry_SetIOVec(PARCBuffer *buffer, struct iovec *iov);
+
+static const uint32_t DEFAULT_CAPACITY = 32;
+
+// ======================================================================================
+// CCNxCodecEncodingBufferLinkedArray releated
+
+static void
+_ccnxCodecEncodingBufferLinkedArray_Display(const _CCNxCodecEncodingBufferLinkedArray *array,
+ int indentation)
+{
+ printf("Entry %p prev %p next %p capacity %u count %u bytes %zu\n",
+ (void *) array, (void *) array->prev, (void *) array->next, array->capacity, array->count, array->bytes);
+
+ size_t totalBytes = 0;
+
+ for (int i = 0; i < array->count; i++) {
+ size_t bytes = array->array[i].vec.iov_len;
+ totalBytes += bytes;
+ printf(" %3d iovec_base=%p bytes=%4zu total bytes=%4zu\n",
+ i, array->array[i].vec.iov_base, bytes, totalBytes);
+ }
+}
+
+static _CCNxCodecEncodingBufferLinkedArray *
+_ccnxCodecEncodingBufferLinkedArray_Create(uint32_t capacity)
+{
+ // allocation for the object plus the array of buffers
+ _CCNxCodecEncodingBufferLinkedArray *array = parcMemory_Allocate(sizeof(_CCNxCodecEncodingBufferLinkedArray));
+ assertNotNull(array, "parcMemory_Allocate(%zu) returned NULL", sizeof(_CCNxCodecEncodingBufferLinkedArray));
+ array->capacity = capacity;
+ array->bytes = 0;
+ array->count = 0;
+ array->next = NULL;
+ array->prev = NULL;
+ array->array = parcMemory_AllocateAndClear(sizeof(_ArrayEntry) * capacity);
+ return array;
+}
+
+/**
+ * A LinkedArray can only be released if it has been removed from the EncodingBuffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecEncodingBufferLinkedArray_Release(_CCNxCodecEncodingBufferLinkedArray **arrayPtr)
+{
+ assertNotNull(arrayPtr, "Parameter must be non-null");
+ _CCNxCodecEncodingBufferLinkedArray *array = *arrayPtr;
+
+ assertNull(array->prev, "array->prev must be null")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ assertNull(array->next, "array->next must be null")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ for (int i = 0; i < array->count; i++) {
+ if (array->array[i].buffer) {
+ parcBuffer_Release(&(array->array[i].buffer));
+ }
+ }
+
+ parcMemory_Deallocate(&(array->array));
+ parcMemory_Deallocate((void **) &array);
+}
+
+static void
+_ccnxCodecEncodingBufferLinkedArray_Validate(const _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ assertNotNull(array, "Parameter list must be non-null");
+
+ if (array->next) {
+ assertTrue(array->next->prev == array,
+ "next->prev does not point to this entry: entry %p next %p next->prev %p",
+ (void *) array, (void *) array->next, (void *) array->next->prev)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+ }
+
+ if (array->prev) {
+ assertTrue(array->prev->next == array,
+ "prev->next does not point to this entry: entry %p prev %p prev->next %p",
+ (void *) array, (void *) array->prev, (void *) array->prev->next)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+ }
+
+ assertTrue(array->count <= array->capacity,
+ "Array count greater than capacity: count %u capacity %u",
+ array->count, array->capacity)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ size_t totalBytes = 0;
+
+ for (int i = 0; i < array->count; i++) {
+ totalBytes += array->array[i].vec.iov_len;
+ }
+
+ assertTrue(totalBytes == array->bytes,
+ "Array bytes wrong, got %zu expected %zu",
+ totalBytes, array->bytes);
+}
+
+__attribute__((unused))
+static void
+_ccnxCodecEncodingBuffer_Validate(CCNxCodecEncodingBuffer *list)
+{
+ assertNotNull(list, "List is null");
+
+ // either we have both a head and a tail or neither
+ assertTrue((list->head && list->tail) || !(list->head || list->tail),
+ "List has a mixture of null head or tail: list %p head %p tail %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+ assertTrue(list->head == NULL || list->head->prev == NULL,
+ "List head has head->prev: list %p head %p head->prev %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+ assertTrue(list->tail == NULL || list->tail->next == NULL,
+ "List tail has tail->next: list %p tail %p tail->next %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+
+ // walk the linked list and make sure the count is equal to what we expect
+ size_t itemCount = 0;
+ size_t totalBytes = 0;
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ _ccnxCodecEncodingBufferLinkedArray_Validate(next);
+
+ itemCount += next->count;
+ totalBytes += next->bytes;
+
+ if (next->next == NULL) {
+ assertTrue(next == list->tail,
+ "Found list link with null next, but it is not tail: list %p list->tail %p entry %p",
+ (void *) list, (void *) list->tail, (void *) next)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ _ccnxCodecEncodingBufferLinkedArray_Display(next, 0);
+ }
+ }
+ next = next->next;
+ }
+
+ assertTrue(itemCount == list->totalCount, "Wrong itemCount, got %zu expected %u", itemCount, list->totalCount);
+ assertTrue(totalBytes == list->totalBytes, "Wrong totalBytes, got %zu expected %zu", totalBytes, list->totalBytes);
+}
+
+
+// ======================================================================================
+
+static void
+_ccnxCodecEncodingBuffer_Remove(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ if (array->prev) {
+ array->prev->next = array->next;
+ }
+
+ if (array->next) {
+ array->next->prev = array->prev;
+ }
+
+ if (list->head == array) {
+ list->head = array->next;
+ } else if (list->tail == array) {
+ list->tail = array->prev;
+ }
+
+ array->next = NULL;
+ array->prev = NULL;
+
+ assertTrue(list->totalBytes >= array->bytes,
+ "list bytes smaller than array: list %zu array %zu", list->totalBytes, array->bytes);
+ assertTrue(list->totalCount >= array->count,
+ "list count smaller than array: list %u array %u", list->totalCount, array->count);
+
+ list->totalCount -= array->count;
+ list->totalBytes -= array->bytes;
+}
+
+static void
+_ccnxCodecEncodingBuffer_FinalRelease(CCNxCodecEncodingBuffer **listBufferPtr)
+{
+ CCNxCodecEncodingBuffer *list = *listBufferPtr;
+
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ _CCNxCodecEncodingBufferLinkedArray *nextnext = next->next;
+ _ccnxCodecEncodingBuffer_Remove(list, next);
+ _ccnxCodecEncodingBufferLinkedArray_Release(&next);
+ next = nextnext;
+ }
+}
+
+parcObject_ExtendPARCObject(CCNxCodecEncodingBuffer, _ccnxCodecEncodingBuffer_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxCodecEncodingBuffer, CCNxCodecEncodingBuffer);
+
+parcObject_ImplementRelease(ccnxCodecEncodingBuffer, CCNxCodecEncodingBuffer);
+
+CCNxCodecEncodingBuffer *
+ccnxCodecEncodingBuffer_Create(void)
+{
+ CCNxCodecEncodingBuffer *listBuffer = parcObject_CreateInstance(CCNxCodecEncodingBuffer);
+ listBuffer->head = NULL;
+ listBuffer->tail = NULL;
+ listBuffer->totalCount = 0;
+ listBuffer->totalBytes = 0;
+ return listBuffer;
+}
+
+void
+ccnxCodecEncodingBuffer_Display(const CCNxCodecEncodingBuffer *list, int indentation)
+{
+ printf("List %p head %p tail %p itemCount %u totalBytes %zu\n",
+ (void *) list, (void *) list->head, (void *) list->tail, list->totalCount, list->totalBytes);
+
+ size_t totalCount = 0;
+ size_t totalBytes = 0;
+ size_t position = 0;
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ printf(" %3zu: entry %p prev %p next %p\n",
+ position, (void *) next, (void *) next->prev, (void *) next->next);
+ _ccnxCodecEncodingBufferLinkedArray_Display(next, indentation);
+
+ totalCount += next->count;
+ totalBytes += next->bytes;
+ position++;
+ next = next->next;
+ }
+}
+
+static void
+_ccnxCodecEncodingBuffer_AppendLinkedArray(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ if (list->tail) {
+ list->tail->next = array;
+ } else {
+ // if list tail is null, it means list head is null too
+ list->head = array;
+ }
+
+ array->prev = list->tail;
+ list->tail = array;
+}
+
+static void
+_ccnxCodecEncodingBuffer_PrependLinkedArray(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ array->next = list->head;
+ array->prev = list->head->prev;
+ list->head->prev = array;
+ list->head = array;
+}
+
+size_t
+ccnxCodecEncodingBuffer_PrependBuffer(CCNxCodecEncodingBuffer *list, PARCBuffer *buffer)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ _CCNxCodecEncodingBufferLinkedArray *head = list->head;
+ if ((head == NULL) || (list->head->count == list->head->capacity)) {
+ head = _ccnxCodecEncodingBufferLinkedArray_Create(DEFAULT_CAPACITY);
+ _ccnxCodecEncodingBuffer_PrependLinkedArray(list, head);
+ }
+
+ assertTrue(head->count < head->capacity, "head does not have any room left")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(head, 0);
+ }
+
+ size_t position = list->head->count;
+ for (int i = 0; i < list->head->count; i++) {
+ head->array[i + 1] = head->array[i];
+ }
+ head->array[0].buffer = parcBuffer_Acquire(buffer);
+ _ccnxCodecEncodingBufferEntry_SetIOVec(buffer, &head->array[0].vec);
+
+ size_t bytes = head->array[0].vec.iov_len;
+ head->bytes += bytes;
+ list->totalBytes += bytes;
+
+ head->count++;
+ list->totalCount++;
+
+ return position;
+}
+
+size_t
+ccnxCodecEncodingBuffer_AppendBuffer(CCNxCodecEncodingBuffer *list, PARCBuffer *buffer)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ _CCNxCodecEncodingBufferLinkedArray *tail = list->tail;
+ if (tail == NULL || list->tail->count == list->tail->capacity) {
+ tail = _ccnxCodecEncodingBufferLinkedArray_Create(DEFAULT_CAPACITY);
+ _ccnxCodecEncodingBuffer_AppendLinkedArray(list, tail);
+ }
+
+ assertTrue(tail->count < tail->capacity, "tail does not have any room left")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(tail, 0);
+ }
+
+ size_t position = list->totalCount;
+ tail->array[tail->count].buffer = parcBuffer_Acquire(buffer);
+ _ccnxCodecEncodingBufferEntry_SetIOVec(buffer, &tail->array[tail->count].vec);
+
+ size_t bytes = tail->array[tail->count].vec.iov_len;
+ tail->bytes += bytes;
+ list->totalBytes += bytes;
+
+ tail->count++;
+ list->totalCount++;
+
+ return position;
+}
+
+// Returns the number of elements in the list
+size_t
+ccnxCodecEncodingBuffer_Size(const CCNxCodecEncodingBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ return buffer->totalCount;
+}
+
+// Returns the total number of bytes in the list
+size_t
+ccnxCodecEncodingBuffer_Length(const CCNxCodecEncodingBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ return buffer->totalBytes;
+}
+
+// ======================================================================================
+
+// ======================================================================================
+
+static void
+_ccnxCodecEncodingBufferEntry_SetIOVec(PARCBuffer *buffer, struct iovec *iov)
+{
+ // this can return NULL for a 0 capacity entry
+ PARCByteArray *byteArray = parcBuffer_Array(buffer);
+
+ if (byteArray) {
+ uint8_t *array = parcByteArray_Array(byteArray);
+
+ // we need to advance the array so it is at the buffer's offset.
+ size_t offset = parcBuffer_ArrayOffset(buffer) + parcBuffer_Position(buffer);
+
+ iov->iov_base = (array + offset);
+ iov->iov_len = parcBuffer_Remaining(buffer);
+ } else {
+ iov->iov_base = NULL;
+ iov->iov_len = 0;
+ }
+}
+
+// Creates an iovec array pointing to the PARCBuffer contents at offset for length
+CCNxCodecEncodingBuffer *
+ccnxCodecEncodingBuffer_Slice(CCNxCodecEncodingBuffer *encodingBuffer, size_t offset, size_t length)
+{
+ CCNxCodecEncodingBuffer *listBuffer = parcObject_CreateInstance(CCNxCodecEncodingBuffer);
+ listBuffer->head = NULL;
+ listBuffer->tail = NULL;
+ listBuffer->totalCount = 0;
+ listBuffer->totalBytes = 0;
+
+ _CCNxCodecEncodingBufferLinkedArray *head;
+ head = _ccnxCodecEncodingBufferLinkedArray_Create(encodingBuffer->totalCount); // pessimistic
+ _ccnxCodecEncodingBuffer_AppendLinkedArray(listBuffer, head);
+
+ _CCNxCodecEncodingBufferLinkedArray *next = encodingBuffer->head;
+ int position = 0;
+ while (next && length) {
+ for (int i = 0; (i < next->count) && length; i++) {
+ if ((offset >= position) && (offset < (position + next->array[i].vec.iov_len))) {
+ int remainder = 0;
+ head->array[head->count].buffer = parcBuffer_Acquire(next->array[i].buffer);
+ head->array[head->count].vec.iov_base = next->array[i].vec.iov_base + (offset - position);
+ remainder = next->array[i].vec.iov_len - (offset - position);
+ if (remainder > length) {
+ remainder = length;
+ }
+ head->array[head->count].vec.iov_len = remainder;
+ offset += remainder;
+ length -= remainder;
+
+ head->count++;
+ head->bytes += remainder;
+ listBuffer->totalCount++;
+ listBuffer->totalBytes += remainder;
+ }
+ position += next->array[i].vec.iov_len;
+ }
+ next = next->next;
+ }
+ if (listBuffer->totalCount == 0) {
+ ccnxCodecEncodingBuffer_Release(&listBuffer);
+ }
+
+ return listBuffer;
+}
+
+// Creates an iovec array pointing to the PARCBuffer contents
+CCNxCodecEncodingBufferIOVec *
+ccnxCodecEncodingBuffer_CreateIOVec(CCNxCodecEncodingBuffer *encodingBuffer)
+{
+ // one allocation for the object and the array
+ size_t totalAllocation = sizeof(CCNxCodecEncodingBufferIOVec) + sizeof(struct iovec) * encodingBuffer->totalCount;
+
+ CCNxCodecEncodingBufferIOVec *vec = parcMemory_Allocate(totalAllocation);
+ assertNotNull(vec, "parcMemory_Allocate(%zu) returned NULL", totalAllocation);
+ vec->encodingBuffer = ccnxCodecEncodingBuffer_Acquire(encodingBuffer);
+ vec->iovcnt = (int) encodingBuffer->totalCount;
+
+ _CCNxCodecEncodingBufferLinkedArray *next = encodingBuffer->head;
+ int position = 0;
+ while (next) {
+ for (int i = 0; i < next->count; i++) {
+ vec->iov[position] = next->array[i].vec;
+ position++;
+ }
+ next = next->next;
+ }
+
+ return vec;
+}
+
+// releases the iovec structure, but does not release the contents. you must
+// keep at least one reference to the parent CCNxCodecEncodingBuffer alive.
+void
+ccnxCodecEncodingBufferIOVec_Release(CCNxCodecEncodingBufferIOVec **iovecPtr)
+{
+ CCNxCodecEncodingBufferIOVec *iov = *iovecPtr;
+ ccnxCodecEncodingBuffer_Release(&iov->encodingBuffer);
+ parcMemory_Deallocate((void **) &iov);
+ *iovecPtr = NULL;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h
new file mode 100644
index 00000000..05563762
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h
@@ -0,0 +1,300 @@
+/*
+ * 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_EncodingBuffer
+ * @brief An encoding buffer is a zero-copy vectored I/O for PARCBuffers
+ *
+ * An Encoding Buffer is an ordered list of PARCBuffers that can be written by functions like
+ * writev(). You can append and append to the list and the buffers are stored only by reference.
+ *
+ * You can also append one encoding buffer to another. In this case, the buffers are moved from
+ * the previous list to the end of the new list.
+ *
+ * @code
+ * {
+ * PARCBuffer *name = parcBuffer_Wrap("marc", 4, 0, 4);
+ * PARCBuffer *space= parcBuffer_Wrap(" ", 1, 0 ,1);
+ * PARCBuffer *email= parcBuffer_Wrap("<marc@example.com>", 18, 0, 18);
+ *
+ * CCNxCodecEncodingBuffer *encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ * ccnxCodecEncodingBuffer_BufferInsertTail(encodingBuffer, name);
+ * ccnxCodecEncodingBuffer_BufferInsertTail(encodingBuffer, space);
+ * parcBuffer_Release(&space);
+ * parcBuffer_Release(&name);
+ *
+ * CCNxCodecEncodingBuffer *emailBuffer = ccnxCodecEncodingBuffer_Create();
+ * ccnxCodecEncodingBuffer_BufferInsertTail(emailBuffer, email);
+ * parcBuffer_Release(&email);
+ *
+ * ccnxCodecEncodingBuffer_MoveToTail(encodingBuffer, emailBuffer);
+ * ccnxCodecEncodingBuffer_Release(&emailBuffer);
+ *
+ * CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(encodingBuffer);
+ * writev(STDOUT_FILENO, iov->iov, iov->iovcnt);
+ * ccnxCodecEncodingBufferIOVec_Release(&iov);
+ *
+ * ccnxCodecEncodingBuffer_Release(&encodingBuffer);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnxCodec_EncodingBuffer_h
+#define libccnx_ccnxCodec_EncodingBuffer_h
+
+#include <sys/uio.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct ccnx_codec_encoding_buffer;
+typedef struct ccnx_codec_encoding_buffer CCNxCodecEncodingBuffer;
+
+/**
+ * @typedef CCNxCodecEncodingBufferIOVec
+ * @abstract Used for writev() or similar functions
+ * @constant encodingBuffer A reference counted copy of the encoding Buffer
+ * @constant iov An allocated array of iovec entries
+ * @constant iovcnt The number of array entries
+ * @discussion <#Discussion#>
+ */
+typedef struct ccnx_tlv_encoding_buffer_iovec {
+ CCNxCodecEncodingBuffer *encodingBuffer;
+ int iovcnt;
+ struct iovec iov[];
+} CCNxCodecEncodingBufferIOVec;
+
+// ======================================================================================
+
+/**
+ * Creates an empty encoding buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-null An allocated encoding buffer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Create(void);
+
+/**
+ * Returns a reference counted copy
+ *
+ * Caller must call ccnxCodecEncodingBuffer_Release() on all copies.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A reference counted copy
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Acquire(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+
+/**
+ * Release the encoding buffer and all internal references
+ *
+ * will release the list and release our reference to all enclosed PARCBuffers
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBuffer_Release(CCNxCodecEncodingBuffer **listBufferPtr);
+
+/**
+ * Displays the structure of the encoding buffer to STDOUT
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBuffer_Display(const CCNxCodecEncodingBuffer *encodingBuffer, int indentation);
+
+/**
+ * Appends a PARCBuffer to the encoding buffer
+ *
+ * Appends to the encoding buffer a reference count to the given buffer.
+ * The return value is the storage node used in the internal data structure.
+ *
+ * The buffer will be used from its position at the time of use (i.e. when
+ * ccnxCodecEncodingBuffer_CreateIOVec() is called). It is important that no other
+ * use of the PARCBuffer move the Position.
+ *
+ * @param [in] encodingBuffer The buffer to append to
+ * @param [in] bufferToInsert The PARCBuffer to insert at the tail of the encoding buffer.
+ *
+ * @return number The position in the encoding buffer list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_AppendBuffer(CCNxCodecEncodingBuffer *encodingBuffer, PARCBuffer *bufferToInsert);
+
+/**
+ * Prepends a PARCBuffer to the encoding buffer
+ *
+ * Prepends to the encoding buffer a reference count to the given buffer.
+ * The return value is the storage node used in the internal data structure.
+ *
+ * The buffer will be used from its position at the time of use (i.e. when
+ * ccnxCodecEncodingBuffer_CreateIOVec() is called). It is important that no other
+ * use of the PARCBuffer move the Position.
+ *
+ * @param [in] encodingBuffer The buffer to prepend to
+ * @param [in] bufferToInsert The PARCBuffer to insert at the head of the encoding buffer.
+ *
+ * @return number The position in the encoding buffer list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_PrependBuffer(CCNxCodecEncodingBuffer *encodingBuffer, PARCBuffer *bufferToPrepend);
+
+/**
+ * Puts the value in scratch memory
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxTlvEncodingbuffer_AppendUint16(CCNxCodecEncodingBuffer *encodingBuffer, uint16_t value);
+
+/**
+ * The number of elements in the list
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_Size(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+/**
+ * The total number of bytes in the list
+ *
+ * This is calculated as the sum of all PARCBuffer Remaining lengths in
+ * the encoding buffer.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_Length(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+// ======================================================================================
+
+/**
+ * Constructs an iovec array based on the buffers in the list
+ *
+ * The elements of the iovec array will be in the list order.
+ * Each iovec entry will point to the backing array of each PARCBuffer
+ * based on that buffers current position.
+ *
+ * This object contains a reference counted copy to the encoding buffer, so
+ * the caller can release the encoding buffer and hold on to only this object
+ * until the writev (or similar function) is done.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The allocated IOVec structure
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBufferIOVec *ccnxCodecEncodingBuffer_CreateIOVec(CCNxCodecEncodingBuffer *encodingBuffer);
+
+/**
+ * Constructs an iovec array based on the buffers in the list that cooresponds to offset and length
+ *
+ * The elements of the iovec array will be in the list order.
+ * Each iovec entry will point to the backing array of each PARCBuffer
+ * based on that buffers current position.
+ *
+ * This object contains a reference counted copy to the encoding buffer, so
+ * the caller can release the encoding buffer and hold on to only this object
+ * until the writev (or similar function) is done.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The allocated IOVec structure
+ * @return null An error, or the specified offset/length is not contained in the extent
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Slice(CCNxCodecEncodingBuffer *encodingBuffer, size_t offset, size_t length);
+
+/**
+ * Release the iovec object.
+ *
+ * This will release the IOVec object and release its reference to the encoding
+ * buffer. If this was the last reference to the encoding buffer, all references to
+ * the underlying PARCBuffers will be released too.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBufferIOVec_Release(CCNxCodecEncodingBufferIOVec **iovecPtr);
+
+#endif // libccnx_ccnxCodec_EncodingBuffer_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c
new file mode 100644
index 00000000..282ec210
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+struct error_messages {
+ CCNxCodecErrorCodes code;
+ const char *message;
+} TlvErrorMessages[] = {
+ { .code = TLV_ERR_NO_ERROR, .message = "No error" },
+ { .code = TLV_ERR_VERSION, .message = "Unsupported version" },
+ { .code = TLV_ERR_PACKETTYPE, .message = "Unsupported packet type" },
+ { .code = TLV_ERR_BEYOND_PACKET_END, .message = "Field goes beyond end of packet" },
+ { .code = TLV_ERR_TOO_LONG, .message = "Length too long for parent container" },
+ { .code = TLV_ERR_NOT_FIXED_SIZE, .message = "Fixed size Type wrong Length" },
+ { .code = TLV_ERR_DUPLICATE_FIELD, .message = "Duplicate field" },
+ { .code = TLV_ERR_EMPTY_SPACE, .message = "The sum of child TLVs did not add up to parent container length" },
+
+ // missing mandatory field errors
+ { .code = TLV_MISSING_MANDATORY, .message = "Missing mandatory field" },
+
+ { .code = TLV_ERR_DECODE, .message = "Decoding error" },
+
+ { .code = TLV_ERR_PACKETLENGTH_TOO_SHORT, .message = "Packet length less than 8" },
+ { .code = TLV_ERR_HEADERLENGTH_TOO_SHORT, .message = "Header length less than 8" },
+ { .code = TLV_ERR_PACKETLENGTHSHORTER, .message = "Packet length less than header length" },
+
+
+ // end of list sentinel, the NULL determines the end of list
+ { .code = UINT16_MAX, .message = NULL }
+};
+
+
+const char *
+ccnxCodecErrors_ErrorMessage(CCNxCodecErrorCodes code)
+{
+ for (int i = 0; TlvErrorMessages[i].message != NULL; i++) {
+ if (TlvErrorMessages[i].code == code) {
+ return TlvErrorMessages[i].message;
+ }
+ }
+ return "No error message found";
+}
+
+// ==========================================================================
+
+struct ccnx_codec_error {
+ CCNxCodecErrorCodes code;
+ const char *functionName;
+ int line;
+ size_t byteOffset;
+ unsigned refcount;
+ char *toString;
+};
+
+CCNxCodecError *
+ccnxCodecError_Create(CCNxCodecErrorCodes code, const char *func, int line, size_t byteOffset)
+{
+ CCNxCodecError *error = parcMemory_AllocateAndClear(sizeof(CCNxCodecError));
+ assertNotNull(error, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecError));
+ error->code = code;
+ error->functionName = func;
+ error->line = line;
+ error->byteOffset = byteOffset;
+ error->toString = NULL; // computed on the fly
+ error->refcount = 1;
+ return error;
+}
+
+CCNxCodecError *
+ccnxCodecError_Acquire(CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter error must be non-null");
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+
+ error->refcount++;
+ return error;
+}
+
+void
+ccnxCodecError_Release(CCNxCodecError **errorPtr)
+{
+ assertNotNull(errorPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*errorPtr, "Parameter must derefernece to non-null pointer");
+ CCNxCodecError *error = *errorPtr;
+
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+ error->refcount--;
+ if (error->refcount == 0) {
+ if (error->toString) {
+ // this is asprintf generated
+ free(error->toString);
+ }
+ parcMemory_Deallocate((void **) &error);
+ }
+ *errorPtr = NULL;
+}
+
+size_t
+ccnxCodecError_GetByteOffset(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->byteOffset;
+}
+
+
+CCNxCodecErrorCodes
+ccnxCodecError_GetErrorCode(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->code;
+}
+
+const char *
+ccnxCodecError_GetFunction(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->functionName;
+}
+
+int
+ccnxCodecError_GetLine(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->line;
+}
+
+const char *
+ccnxCodecError_GetErrorMessage(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return ccnxCodecErrors_ErrorMessage(error->code);
+}
+
+const char *
+ccnxCodecError_ToString(CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ if (error->toString) {
+ return error->toString;
+ }
+
+ int failure = asprintf(&error->toString, "TLV error: %s:%d offset %zu: %s",
+ error->functionName,
+ error->line,
+ error->byteOffset,
+ ccnxCodecError_GetErrorMessage(error));
+ assertTrue(failure > -1, "Error asprintf");
+
+ return error->toString;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h
new file mode 100755
index 00000000..7204cedb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h
@@ -0,0 +1,190 @@
+/*
+ * 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_Error.h
+ * @brief Wraps an error condition in the Tlv codec
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_ccnxCodec_Error_h
+#define libccnx_ccnxCodec_Error_h
+
+#include <stdlib.h>
+#include <ccnx/common/codec/ccnxCodec_ErrorCodes.h>
+
+struct ccnx_codec_error;
+typedef struct ccnx_codec_error CCNxCodecError;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_ErrorMessage(CCNxCodecErrorCodes code);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecError_Create(CCNxCodecErrorCodes code, const char *func, int line, size_t byteOffset);
+
+/**
+ * Returns a reference counted copy of the error
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A reference counted copy
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecError_Acquire(CCNxCodecError *error);
+
+/**
+ * Releases a reference count
+ *
+ * When the reference count reaches 0, the object is destroyed.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecError_Release(CCNxCodecError **errorPtr);
+
+/**
+ * The byte offset of the error
+ *
+ * Primarily for decoding errors. It will contain the byte offset of the first byte
+ * of the field causing the error. For encoding, it will be the byte offer of the
+ * partially-encoded buffer, but the error is usually in the native format, not the
+ * partially encoded buffer.
+ *
+ * @param <#param1#>
+ * @return The byte offset of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecError_GetByteOffset(const CCNxCodecError *error);
+
+
+/**
+ * If there was a decode error, return the error code
+ *
+ * A text message is available from <code>tlvErrors_ErrorMessage()</code>.
+ *
+ * @param <#param1#>
+ * @return Returns the error code, or TVL_ERR_NO_ERROR for successful decode
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecErrorCodes ccnxCodecError_GetErrorCode(const CCNxCodecError *error);
+
+/**
+ * The function where the error occured
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_GetFunction(const CCNxCodecError *error);
+
+/**
+ * The line where the error occured
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecError_GetLine(const CCNxCodecError *error);
+
+/**
+ * Descriptive error message
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return A static text string
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_GetErrorMessage(const CCNxCodecError *error);
+
+/**
+ * A string representation of the entire error
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An internally allocated string, do not destroy it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_ToString(CCNxCodecError *error);
+#endif // libccnx_ccnx_TlvError_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h b/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h
new file mode 100755
index 00000000..938f6b20
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h
@@ -0,0 +1,55 @@
+/*
+ * 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_ErrorCodes.h
+ * @brief The error codes used by CCNxCodecError.
+ *
+ * The codecs in schema_v0 and schema_v1 use these error codes to report problems inside
+ * CCNxCodec_TlvEncoder and CCNxCodec_TlvDecoder.
+ *
+ */
+
+#ifndef CCNx_Common_ccnxCodec_ErrorCodes_h
+#define CCNx_Common_ccnxCodec_ErrorCodes_h
+
+/**
+ * @typedef <#CCNBHeaderType#>
+ * @abstract <#Abstract#>
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum ccnx_codec_error_codes {
+ TLV_ERR_NO_ERROR,
+ TLV_ERR_VERSION,
+ TLV_ERR_PACKETTYPE,
+ TLV_ERR_BEYOND_PACKET_END,
+ TLV_ERR_TOO_LONG,
+ TLV_ERR_NOT_FIXED_SIZE,
+ TLV_ERR_DUPLICATE_FIELD,
+ TLV_ERR_EMPTY_SPACE,
+
+ // generic error for decoding error
+ TLV_ERR_DECODE,
+
+ TLV_ERR_PACKETLENGTH_TOO_SHORT,
+ TLV_ERR_HEADERLENGTH_TOO_SHORT,
+ TLV_ERR_PACKETLENGTHSHORTER,
+
+
+ // errors for missing mandatory fields
+ TLV_MISSING_MANDATORY,
+} CCNxCodecErrorCodes;
+#endif
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c
new file mode 100755
index 00000000..ea1868b6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c
@@ -0,0 +1,809 @@
+/*
+ * 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.
+ */
+
+/**
+ * We maintain a linked list of memory blocks. We fill each memory block to capacity, then
+ * allocate another memory block, putting it at the tail of the list.
+ *
+ * We maintain a "current" pointer to the memory block that holds "position". Insertions always go
+ * current block.
+ *
+ * Each memory block has a capacity and a limit. The capacity is the maximum number of bytes available.
+ * The limit is the furthest byte written. It will not exceed the capacity..
+ *
+ * Once a memory block has a "next" block, the limit is fixed. One cannot shrink or expand the limit.
+ * When the "next" pointer is set, the capacity is shrunk to the limit and the buffer is called "frozen".
+ *
+ * (always in ABSOLUTE bytes)
+ * position = 4036
+ * begin = 0 begin = 1536 begin = 3536 |
+ * | | | |
+ * +--------------------------+--------------------------+--------------------------+
+ * | block 0 | block 1 | block 2 |
+ * +--------------------------+--------------------------+--------------------------+
+ * | | | |
+ * capacity = 1536 capacity = 2000 | capacity = 2046
+ * limit = 1536 limit = 2000 limit = 500
+ * (always in RELATIVE bytes)
+ *
+ * Block 0 was allocated at 1536 bytes and filled to capacity before it was frozen.
+ *
+ * Block 1 was allocated at 2046 but only filled to 2000 bytes when it was frozen. The last 46 bytes
+ * of the block are permanently lost.
+ *
+ * Block 2 is still in use. 500 bytes have been written out of the 2046 capacity.
+ *
+ * The "begin" of a memory block is equal to the previous's memory block's "begin" plus
+ * the previous blocks "limit" when it is frozen. The "begin" value is absolute byte position
+ * and it will never change because all prior blocks must be frozen.
+ *
+ * The total "limit" of the entire chain is the tail's "begin" plus tail's "limit".
+ *
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+struct ccnx_codec_network_buffer_memory;
+typedef struct ccnx_codec_network_buffer_memory CCNxCodecNetworkBufferMemory;
+
+struct ccnx_codec_network_buffer_memory {
+ CCNxCodecNetworkBufferMemory *next;
+
+ size_t begin; /**< Absolute position of begining */
+ size_t limit; /**< Bytes used */
+ size_t capacity; /**< maximum bytes available (end - begin) */
+
+ uint8_t *memory;
+};
+
+struct ccnx_codec_network_buffer_iovec {
+ CCNxCodecNetworkBuffer *networkBuffer;
+ unsigned refcount;
+ size_t totalBytes;
+ int iovcnt;
+ struct iovec array[];
+};
+
+struct ccnx_codec_network_buffer {
+ size_t position;
+ size_t capacity; /**< Bytes allocated */
+
+ CCNxCodecNetworkBufferMemory *current;
+ CCNxCodecNetworkBufferMemory *head;
+ CCNxCodecNetworkBufferMemory *tail;
+
+ void *userarg;
+ CCNxCodecNetworkBufferMemoryBlockFunctions memoryFunctions;
+ unsigned refcount;
+};
+
+// ================================================================================
+
+#define INLINE_POSITION(block) ((uint8_t *) block + sizeof(CCNxCodecNetworkBufferMemory))
+
+static CCNxCodecNetworkBufferMemory *
+_ccnxCodecNetworkBufferMemory_Allocate(CCNxCodecNetworkBuffer *buffer, size_t bytes)
+{
+ assertNotNull(buffer->memoryFunctions.allocator, "Allocator must be non-null to allocate memory!");
+
+ CCNxCodecNetworkBufferMemory *block;
+ size_t totalAllocation = bytes + sizeof(CCNxCodecNetworkBufferMemory);
+ size_t actual = buffer->memoryFunctions.allocator(buffer->userarg, totalAllocation, (void **) &block);
+
+ if (actual > sizeof(CCNxCodecNetworkBufferMemory)) {
+ block->next = NULL;
+ block->begin = 0;
+ block->capacity = actual - sizeof(CCNxCodecNetworkBufferMemory);
+ block->limit = 0;
+
+ block->memory = INLINE_POSITION(block);
+ return block;
+ }
+
+ // Need a de-allocator, see case 1006
+ trapOutOfMemory("Wanted %zu got %zu, minimum required %zu", totalAllocation, actual, sizeof(CCNxCodecNetworkBufferMemory));
+ return NULL;
+}
+
+/**
+ * Wrap a user-provided buffer. It will be de-allocated with the buffer memory functions.
+ *
+ * The capacity = limit = length of the user provided memory.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static CCNxCodecNetworkBufferMemory *
+_ccnxCodecNetworkBufferMemory_Wrap(CCNxCodecNetworkBuffer *buffer, size_t length, uint8_t memory[length])
+{
+ CCNxCodecNetworkBufferMemory *block = parcMemory_AllocateAndClear(sizeof(CCNxCodecNetworkBufferMemory));
+ if (block) {
+ block->next = NULL;
+ block->begin = 0;
+ block->capacity = length;
+ block->limit = length;
+ block->memory = memory;
+
+ return block;
+ }
+ trapOutOfMemory("Could not allocate a CCNxCodecNetworkBufferMemory");
+}
+
+/**
+ * Releases a memory block
+ *
+ * The memory block must not be in a linked list (i.e memory->next must be NULL)
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecNetworkBufferMemory_Release(CCNxCodecNetworkBuffer *buffer, CCNxCodecNetworkBufferMemory **memoryPtr)
+{
+ assertNotNull(memoryPtr, "Parameter must be non-null");
+ assertNotNull(*memoryPtr, "Parameter must dereference to non-null");
+
+ CCNxCodecNetworkBufferMemory *memory = *memoryPtr;
+
+ assertNull(memory->next, "memory->next is not null");
+
+ // If the memory is not in-line, free it with the deallocator
+ if (memory->memory == INLINE_POSITION(memory)) {
+ if (buffer->memoryFunctions.deallocator) {
+ buffer->memoryFunctions.deallocator(buffer->userarg, (void **) memoryPtr);
+ }
+ } else {
+ if (buffer->memoryFunctions.deallocator) {
+ buffer->memoryFunctions.deallocator(buffer->userarg, (void **) &memory->memory);
+ }
+ parcMemory_Deallocate((void **) &memory);
+ }
+
+
+ *memoryPtr = NULL;
+}
+
+static void
+_ccnxCodecNetworkBufferMemory_Display(const CCNxCodecNetworkBufferMemory *block, unsigned indent)
+{
+ assertNotNull(block, "Parameter block must be non-null");
+
+ printf("Memory block %p next %p offset %zu limit %zu capacity %zu\n",
+ (void *) block, (void *) block->next, block->begin, block->limit, block->capacity);
+
+ longBowDebug_MemoryDump((const char *) block->memory, block->capacity);
+}
+
+static bool
+_ccnxCodecNetworkBufferMemory_ContainsPosition(CCNxCodecNetworkBufferMemory *memory, size_t position)
+{
+ return (memory->begin <= position && position < memory->begin + memory->limit);
+}
+
+// ================================================================================
+
+static void
+_ccnxCodecNetworkBuffer_Expand(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t allocationSize = 2048;
+ CCNxCodecNetworkBufferMemory *memory = _ccnxCodecNetworkBufferMemory_Allocate(buffer, allocationSize);
+
+ buffer->capacity += memory->capacity;
+
+ memory->begin = buffer->tail->begin + buffer->tail->limit;
+
+ // this will free the tail buffer. We will drop its capacity to its limit.
+ buffer->tail->next = memory;
+ buffer->tail->capacity = buffer->tail->limit;
+
+ buffer->tail = memory;
+}
+
+static size_t
+_ccnxCodecNetworkBuffer_RemainingCurrentBlock(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t remaining = buffer->current->begin + buffer->current->capacity - buffer->position;
+ return remaining;
+}
+
+static size_t
+_ccnxCodecNetworkBuffer_BlockCount(CCNxCodecNetworkBuffer *buffer)
+{
+ // we should store this count for faster access
+ size_t count = 0;
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block) {
+ count++;
+ block = block->next;
+ }
+ return count;
+}
+
+static void
+_ccnxCodecNetworkBuffer_AllocateIfNeeded(CCNxCodecNetworkBuffer *buffer)
+{
+ if (buffer->position == buffer->current->begin + buffer->current->capacity) {
+ if (buffer->current->next) {
+ buffer->current = buffer->current->next;
+ } else {
+ // we are at the end of the current buffer and there's nothing beyond,
+ // so allocate another memory block
+ _ccnxCodecNetworkBuffer_Expand(buffer);
+ buffer->current = buffer->tail;
+ }
+ }
+}
+
+/**
+ * Check if we can fit 'length' bytes in contiguous memory.
+ *
+ * If we cannot, and the remaining buffer space in the current buffer is small, freeze it out
+ * and allocate a new buffer. Otherwise if the difference is large, do not freeze it and the
+ * write will span memory blocks.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecNetworkBuffer_EnsureRemaining(CCNxCodecNetworkBuffer *buffer, size_t length)
+{
+ // If the current block as a next pointer, then the remaining is from
+ // the position to the limit. Otherwise it is from the position to
+ // the end.
+
+ size_t remaining;
+ remaining = buffer->current->begin + buffer->current->capacity - buffer->position;
+
+
+ if (remaining < length) {
+ // If its a small amount of memory to waste, we'll freeze the curent buffer and
+ // make a new one.
+ if (length < 32 && buffer->current->next == NULL) {
+ _ccnxCodecNetworkBuffer_Expand(buffer);
+ buffer->current = buffer->tail;
+ return;
+ }
+
+ // otherwise, thre is still space in the current buffer, even though it is not
+ // long enough. The writer will just need to span the two memory blocks.
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+ }
+}
+
+
+// ================================================================================
+
+static size_t
+_ccnxCodecNetworkBuffer_ParcMemoryAllocator(void *userarg, size_t bytes, void **output)
+{
+ *output = parcMemory_Allocate(bytes);
+ if (*output) {
+ return bytes;
+ }
+ return 0;
+}
+
+static void
+_ccnxCodecNetworkBuffer_ParcMemoryDeallocator(void *userarg, void **memoryPtr)
+{
+ void *memory = *memoryPtr;
+ parcMemory_Deallocate((void **) &memory);
+ *memoryPtr = NULL;
+}
+
+const CCNxCodecNetworkBufferMemoryBlockFunctions ParcMemoryMemoryBlock = {
+ .allocator = &_ccnxCodecNetworkBuffer_ParcMemoryAllocator,
+ .deallocator = &_ccnxCodecNetworkBuffer_ParcMemoryDeallocator
+};
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Allocate(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg)
+{
+ CCNxCodecNetworkBuffer *buffer = parcMemory_Allocate(sizeof(CCNxCodecNetworkBuffer));
+ assertNotNull(buffer, "parcMemory_Allocate(%zu) returned NULL", sizeof(CCNxCodecNetworkBuffer));
+ buffer->refcount = 1;
+ buffer->position = 0;
+ memcpy(&buffer->memoryFunctions, memoryFunctions, sizeof(CCNxCodecNetworkBufferMemoryBlockFunctions));
+ buffer->userarg = userarg;
+ return buffer;
+}
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Create(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg)
+{
+ CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Allocate(memoryFunctions, userarg);
+
+ buffer->head = _ccnxCodecNetworkBufferMemory_Allocate(buffer, 1536);
+ buffer->tail = buffer->head;
+ buffer->current = buffer->head;
+ buffer->capacity = buffer->head->capacity;
+
+ return buffer;
+}
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_CreateFromArray(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg, size_t length, uint8_t memory[length])
+{
+ CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Allocate(memoryFunctions, userarg);
+
+ buffer->head = _ccnxCodecNetworkBufferMemory_Wrap(buffer, length, memory);
+ buffer->tail = buffer->head;
+ buffer->current = buffer->head;
+ buffer->capacity = buffer->head->capacity;
+
+ return buffer;
+}
+
+
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Acquire(CCNxCodecNetworkBuffer *original)
+{
+ assertNotNull(original, "Parameter must be non-null");
+ assertTrue(original->refcount > 0, "Refcount must be positive, got 0");
+
+ original->refcount++;
+ return original;
+}
+
+void
+ccnxCodecNetworkBuffer_Release(CCNxCodecNetworkBuffer **bufferPtr)
+{
+ assertNotNull(bufferPtr, "Parameter must be non-null");
+ assertNotNull(*bufferPtr, "Parameter must dereference to non-null");
+
+ CCNxCodecNetworkBuffer *buffer = *bufferPtr;
+ assertTrue(buffer->refcount > 0, "refcount must be positive");
+
+ buffer->refcount--;
+ if (buffer->refcount == 0) {
+ while (buffer->head) {
+ CCNxCodecNetworkBufferMemory *next = buffer->head->next;
+ buffer->head->next = NULL;
+ _ccnxCodecNetworkBufferMemory_Release(buffer, &buffer->head);
+ buffer->head = next;
+ }
+ parcMemory_Deallocate((void **) &buffer);
+ }
+ *bufferPtr = NULL;
+}
+
+// ================================================================================
+
+static inline size_t
+_ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer)
+{
+ return buffer->tail->begin + buffer->tail->limit;
+}
+
+size_t
+ccnxCodecNetworkBuffer_Position(const CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be non-null");
+ return buffer->position;
+}
+
+size_t
+ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be non-null");
+ return _ccnxCodecNetworkBuffer_Limit(buffer);
+}
+
+void
+ccnxCodecNetworkBuffer_SetPosition(CCNxCodecNetworkBuffer *buffer, size_t position)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(position <= _ccnxCodecNetworkBuffer_Limit(buffer), "Position must not exceed limit, got %zu limit %zu",
+ position, _ccnxCodecNetworkBuffer_Limit(buffer));
+
+ // We allow the position to be set to the end (just past the last written byte) of the buffer.
+ // This is the "next" position to be written
+ if (position == _ccnxCodecNetworkBuffer_Limit(buffer)) {
+ buffer->current = buffer->tail;
+ } else {
+ // Is the new position within the current memory block?
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(buffer->current, position)) {
+ // we're ok, new position is in this buffer, we're done :)
+ } else {
+ // we need to find the right buffer
+ CCNxCodecNetworkBufferMemory *memory = buffer->head;
+ while (!_ccnxCodecNetworkBufferMemory_ContainsPosition(memory, position)) {
+ memory = memory->next;
+ assertNotNull(memory, "Illegal state: position < buffer->limit, but we ran off end of linked list");
+ }
+
+ buffer->current = memory;
+ }
+ }
+
+ buffer->position = position;
+}
+
+void
+ccnxCodecNetworkBuffer_Finalize(CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ // if we're at the limit, we're done
+ if (buffer->position < _ccnxCodecNetworkBuffer_Limit(buffer)) {
+ // begin at the tail and free memory blocks until we've found the current position
+ size_t position = buffer->position;
+
+ // Is the new position within the current memory block?
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(buffer->current, position)) {
+ // we're ok, new position is in this buffer, we're done :)
+ } else {
+ // we need to find the right buffer
+ CCNxCodecNetworkBufferMemory *memory = buffer->head;
+ while (!_ccnxCodecNetworkBufferMemory_ContainsPosition(memory, position)) {
+ memory = memory->next;
+ assertNotNull(memory, "Illegal state: position < buffer->limit, but we ran off end of linked list");
+ }
+
+ buffer->current = memory;
+ }
+
+ // discard any memory blocks after this
+
+ CCNxCodecNetworkBufferMemory *current = buffer->current->next;
+ while (current) {
+ CCNxCodecNetworkBufferMemory *next = current->next;
+
+ // this is a requirement for _Release to not throw an assertion
+ current->next = NULL;
+ _ccnxCodecNetworkBufferMemory_Release(buffer, &current);
+ current = next;
+ }
+
+ // Set the limit of the current block so buffer->position is the end
+ buffer->current->next = NULL;
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ buffer->current->limit = relativePosition;
+ buffer->tail = buffer->current;
+ }
+}
+
+static inline void
+_ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value)
+{
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ buffer->current->memory[relativePosition++] = value;
+ if (relativePosition > buffer->current->limit) {
+ buffer->current->limit = relativePosition;
+ }
+
+ buffer->position++;
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint16(CCNxCodecNetworkBuffer *buffer, uint16_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 2);
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value >> 8);
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint32(CCNxCodecNetworkBuffer *buffer, uint32_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 4);
+
+ for (int i = sizeof(uint32_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, b);
+ }
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint64(CCNxCodecNetworkBuffer *buffer, uint64_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 8);
+
+ for (int i = sizeof(uint64_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, b);
+ }
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutArray(CCNxCodecNetworkBuffer *buffer, size_t length, const uint8_t array[length])
+{
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+
+ size_t offset = 0;
+ while (offset < length) {
+ size_t available = _ccnxCodecNetworkBuffer_RemainingCurrentBlock(buffer);
+ if (available == 0) {
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+ } else {
+ if (available > (length - offset)) {
+ available = length - offset;
+ }
+
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ void *dest = &buffer->current->memory[relativePosition];
+ const void *src = &array[offset];
+ memcpy(dest, src, available);
+
+ relativePosition += available;
+ if (relativePosition > buffer->current->limit) {
+ buffer->current->limit = relativePosition;
+ }
+
+ buffer->position += available;
+ offset += available;
+ }
+ }
+}
+
+void
+ccnxCodecNetworkBuffer_PutBuffer(CCNxCodecNetworkBuffer *buffer, PARCBuffer *value)
+{
+ size_t length = parcBuffer_Remaining(value);
+ if (length > 0) {
+ void *ptr = parcBuffer_Overlay(value, 0);
+ ccnxCodecNetworkBuffer_PutArray(buffer, length, ptr);
+ }
+}
+
+PARCBuffer *
+ccnxCodecNetworkBuffer_CreateParcBuffer(CCNxCodecNetworkBuffer *buffer)
+{
+ // We don't have the idea of Flip here yet, so we go from 0 .. position
+
+ size_t length = _ccnxCodecNetworkBuffer_Limit(buffer);
+ PARCBuffer *output = parcBuffer_Allocate(length);
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block) {
+ size_t available = (length > block->limit) ? block->limit : length;
+ if (available > 0) {
+ parcBuffer_PutArray(output, available, block->memory);
+ }
+ length -= available;
+ block = block->next;
+ }
+ parcBuffer_Flip(output);
+ return output;
+}
+
+PARCSignature *
+ccnxCodecNetworkBuffer_ComputeSignature(CCNxCodecNetworkBuffer *buffer, size_t start, size_t end, PARCSigner *signer)
+{
+ // Most positions (start, end, position, roof) below are in **absolute** coordinates
+ // The position relativePosition is relative to the memory block start
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(end >= start, "End is less than start: start %zu end %zu", start, end);
+
+ PARCSignature *signature = NULL;
+ if (signer) {
+ // compute the signature over the specified area
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+
+ size_t position = start;
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block && position < block->begin + block->limit) {
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(block, position)) {
+ // determine if we're going all the way to the block's end or are we
+ // stopping early because that's the end of the designated area
+ size_t roof = (end > block->begin + block->limit) ? block->limit : end;
+ size_t length = roof - position;
+
+ // now calculate the relative offset in the block so we can update the hash
+ size_t relativePosition = position - block->begin;
+
+ parcCryptoHasher_UpdateBytes(hasher, &block->memory[relativePosition], length);
+
+ position += length;
+ }
+
+ block = block->next;
+ }
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ signature = parcSigner_SignDigest(signer, hash);
+ parcCryptoHash_Release(&hash);
+ }
+
+ return signature;
+}
+
+uint8_t
+ccnxCodecNetworkBuffer_GetUint8(const CCNxCodecNetworkBuffer *netbuff, size_t position)
+{
+ assertNotNull(netbuff, "Parameter buffer must be non-null");
+ assertTrue(position < _ccnxCodecNetworkBuffer_Limit(netbuff), "Position %zu beyond limit %zu", position, _ccnxCodecNetworkBuffer_Limit(netbuff));
+
+ CCNxCodecNetworkBufferMemory *block = netbuff->head;
+ while (block && !_ccnxCodecNetworkBufferMemory_ContainsPosition(block, position)) {
+ block = block->next;
+ }
+
+ trapUnexpectedStateIf(block == NULL,
+ "Could not find position %zu that is less than limit %zu",
+ position, _ccnxCodecNetworkBuffer_Limit(netbuff));
+
+ size_t relativeOffset = position - block->begin;
+ return block->memory[relativeOffset];
+}
+
+void
+ccnxCodecNetworkBuffer_Display(const CCNxCodecNetworkBuffer *netbuff, unsigned indent)
+{
+ printf("CCNxCodecNetworkBuffer %p head %p current %p tail %p\n",
+ (void *) netbuff, (void *) netbuff->head, (void *) netbuff->current, (void *) netbuff->tail);
+ printf(" position %zu limit %zu capacity %zu refcount %u userarg %p\n",
+ netbuff->position, _ccnxCodecNetworkBuffer_Limit(netbuff), netbuff->capacity, netbuff->refcount, netbuff->userarg);
+
+ CCNxCodecNetworkBufferMemory *block = netbuff->head;
+ while (block) {
+ _ccnxCodecNetworkBufferMemory_Display(block, 6);
+ block = block->next;
+ }
+}
+
+// ======================================================================================
+
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecNetworkBuffer_CreateIoVec(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t blockCount = _ccnxCodecNetworkBuffer_BlockCount(buffer);
+ size_t allocationSize = sizeof(CCNxCodecNetworkBufferIoVec) + sizeof(struct iovec) * blockCount;
+
+ CCNxCodecNetworkBufferIoVec *vec = parcMemory_Allocate(allocationSize);
+ assertNotNull(vec, "parcMemory_Allocate(%zu) returned NULL", allocationSize);
+ vec->refcount = 1;
+ vec->networkBuffer = ccnxCodecNetworkBuffer_Acquire(buffer);
+ vec->iovcnt = (int) blockCount;
+ vec->totalBytes = 0;
+
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ for (int i = 0; i < vec->iovcnt; i++) {
+ vec->array[i].iov_base = block->memory;
+ vec->array[i].iov_len = block->limit;
+ vec->totalBytes += block->limit;
+ block = block->next;
+ }
+
+ return vec;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecNetworkBufferIoVec_Acquire(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ assertTrue(vec->refcount > 0, "Existing reference count is 0");
+ vec->refcount++;
+ return vec;
+}
+
+void
+ccnxCodecNetworkBufferIoVec_Release(CCNxCodecNetworkBufferIoVec **vecPtr)
+{
+ assertNotNull(vecPtr, "Parameter must be non-null");
+ assertNotNull(*vecPtr, "Parameter must dereference to non-null");
+ CCNxCodecNetworkBufferIoVec *vec = *vecPtr;
+ assertTrue(vec->refcount > 0, "object has 0 refcount!");
+
+ vec->refcount--;
+ if (vec->refcount == 0) {
+ ccnxCodecNetworkBuffer_Release(&vec->networkBuffer);
+ parcMemory_Deallocate((void **) &vec);
+ }
+ *vecPtr = NULL;
+}
+
+int
+ccnxCodecNetworkBufferIoVec_GetCount(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->iovcnt;
+}
+
+const struct iovec *
+ccnxCodecNetworkBufferIoVec_GetArray(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->array;
+}
+
+void
+ccnxCodecNetworkBufferIoVec_Display(const CCNxCodecNetworkBufferIoVec *vec, int indent)
+{
+ printf("\nCCNxCodecNetworkBufferIoVec %p refcount %u totalBytes %zu iovcnt %d NetworkBuffer %p\n",
+ (void *) vec, vec->refcount, vec->totalBytes, vec->iovcnt, (void *) vec->networkBuffer);
+
+ size_t total = 0;
+ for (int i = 0; i < vec->iovcnt; i++) {
+ total += vec->array[i].iov_len;
+ int nwritten = printf(" vec %3d base %p length %5zu total %5zu\n", i, (void *) vec->array[i].iov_base, vec->array[i].iov_len, total);
+ assertTrue(nwritten >= 0, "Error calling printf");
+ longBowDebug_MemoryDump(vec->array[i].iov_base, vec->array[i].iov_len);
+ }
+}
+
+size_t
+ccnxCodecNetworkBufferIoVec_Length(const CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->totalBytes;
+}
+
+bool
+ccnxCodecNetworkBufferIoVec_Equals(const CCNxCodecNetworkBufferIoVec *a, const CCNxCodecNetworkBufferIoVec *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ // both are non-null
+ bool equals = false;
+ if (a->totalBytes == b->totalBytes) {
+ PARCBuffer *abuffer = ccnxCodecNetworkBuffer_CreateParcBuffer(a->networkBuffer);
+ PARCBuffer *bbuffer = ccnxCodecNetworkBuffer_CreateParcBuffer(b->networkBuffer);
+
+ equals = parcBuffer_Equals(abuffer, bbuffer);
+
+ parcBuffer_Release(&abuffer);
+ parcBuffer_Release(&bbuffer);
+ }
+ return equals;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h
new file mode 100644
index 00000000..3ac1fffd
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h
@@ -0,0 +1,833 @@
+/*
+ * 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 codec/ccnxCodec_NetworkBuffer.h
+ * @brief A network buffer represents memory used for network I/O
+ *
+ * A network buffer represents memory used for network I/O and may be scatter/gather non-contiguous memory or
+ * may be made up for special memory regions, such as DMA memory directly from the kernel.
+ *
+ * The general usage pattern of this is to create the network buffer, fill it in with the encoded packet, then
+ * create a CCNxCodecNetworkBufferIoVec from it. The IoVec is then used in a gathering write. Calling ccnxCodecNetworkBuffer_CreateIoVec()
+ * will create a CCNxCodecNetworkBufferIoVec object that has a reference to the original network buffer and will release it when the
+ * IoVec is released. A user can get a normal system "struct iovec" from the CCNxCodecNetworkBufferIoVec.
+ *
+ * The CCNxCodecNetworkBufferIoVec is a read-only object.
+ *
+ * A network buffer uses a CCNxCodecNetworkBufferMemoryBlockFunctions structure for an allocator and de-allocator. The allocator is called
+ * to add more memory to the scatter/gather list of memory buffers and the de-allocator is used to return those
+ * buffers to the owner. A user could point to "ParcMemoryMemoryBlock" to use the normal parcMemory_allocate() and
+ * parcMemory_deallocate() functions. Or, they can use their own or wrap event buffers or wrap kernel memory blocks.
+ *
+ * The user can address the memory using a linearized position with ccnxCodecNetworkBuffer_Position() and ccnxCodecNetworkBuffer_SetPosition().
+ * If a write would span two (or more) memory blocks, the write function will correctly split the write.
+ *
+ * When doing a write that would span two memory blocks, the network buffer may choose to truncate the current block and do an
+ * unsplit write to the second block. It will only do this if it would result in a small amount of wasted memory. This can only
+ * be done on the first pass through a memory block (if you set the position backwards and do a write that splits over memory blocks,
+ * the write must be split).
+ *
+ * Add a control to turn off the "optimized" write splitting (i.e. the behavior to truncate the current block and do an unsplit
+ * write to the next block).
+ *
+ * ccnxCodecNetworkBuffer_ComputeSignature should be factored out of here, like the verifier is factored out
+ *
+ */
+#ifndef Libccnx_codec_ccnxCodecNetworkBuffer_h
+#define Libccnx_codec_ccnxCodecNetworkBuffer_h
+
+#include <stdint.h>
+#include <sys/uio.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+struct ccnx_codec_network_buffer;
+/**
+ * @typedef CCNxCodecNetworkBuffer
+ * @brief A network buffer represents memory used for network I/O.
+ */
+typedef struct ccnx_codec_network_buffer CCNxCodecNetworkBuffer;
+
+struct ccnx_codec_network_buffer_iovec;
+/**
+ * @typedef CCNxCodecNetworkBufferIoVec
+ * @brief Contains a sequence of buffers to read in which the data to be read is stored.
+ */
+typedef struct ccnx_codec_network_buffer_iovec CCNxCodecNetworkBufferIoVec;
+
+/**
+ * @typedef CCNxCodecNetworkBufferMemoryBlockFunctions
+ * @brief Structure and functions for MemoryBlocks
+ */
+
+typedef struct ccnx_codec_network_buffer_memory_block_struct {
+ /**
+ * Allocate a block of memory at least 'bytes' long.
+ *
+ * @param [in] userarg Closure, may be null.
+ * @param [in] bytes The requested number of bytes.
+ * @param [out] output The buffer to set.
+ *
+ * @return The number of bytes granted in output.
+ */
+ size_t (*allocator)(void *userarg, size_t bytes, void **output);
+
+ /**
+ * Returns (frees) a memory block.
+ *
+ * @param [in] userarg Closure, may be null.
+ * @param [out] memoryPtr The memory pointer to dellocate and NULLify.
+ */
+ void (*deallocator)(void *userarg, void **memoryPtr);
+} CCNxCodecNetworkBufferMemoryBlockFunctions;
+
+extern const CCNxCodecNetworkBufferMemoryBlockFunctions ParcMemoryMemoryBlock;
+
+/**
+ * Creates a `CCNxCodecNetworkBuffer`.
+ *
+ * The first memory block is allocated using the default settings. The parameter "userarg" will be passed
+ * to the CCNxCodecNetworkBufferMemoryBlockFunctions for allocations and de-allocations.
+ *
+ * @param [in] blockFunctions The allocator/de-allocator to use.
+ * @param [in] userarg Passed to all calls to the blockFunctions, may be NULL.
+ *
+ * @return non-null An allocated memory block using memory from blockFunctions.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer * netbuffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_Create(const CCNxCodecNetworkBufferMemoryBlockFunctions *blockFunctions, void *userarg);
+
+/**
+ * Create a `CCNxCodecNetworkBuffer` from a buffer block.
+ *
+ * The first memory block of the Network Buffer will wrap the user provided memory.
+ *
+ * If the allocator is non-null then the user could append more memory blocks.
+ *
+ * The deallocator in the blockFunctions will be called on the memory when done. The userarg will
+ * be passed to the CCNxCodecNetworkBufferMemoryBlockFunctions.
+ *
+ * @param [in] blockFunctions The allocator/de-allocator to use.
+ * @param [in] userarg Passed to all calls to the blockFunctions, may be NULL.
+ * @param [in] length The length of the user-provided memory.
+ * @param [in] memory The user-provided memory.
+ *
+ * @return non-null An allocated memory block that wraps the user-provided memory.
+ * @return null An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_CreateFromArray(const CCNxCodecNetworkBufferMemoryBlockFunctions *blockFunctions, void *userarg, size_t length, uint8_t *memory);
+
+/**
+ * Increase the number of references to a `CCNxCodecNetworkBuffer`.
+ *
+ * Note that new `CCNxCodecNetworkBuffer` is not created,
+ * only that the given `CCNxCodecNetworkBuffer` reference count is incremented.
+ * Discard the reference by invoking `ccnxCodecNetworkBuffer_Release`.
+ *
+ * @param [in] original A pointer to a `CCNxCodecNetworkBuffer` instance.
+ *
+ * @return The input `CCNxCodecNetworkBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * CCNxCodecNetworkBuffer *handle = ccnxCodecNetworkBuffer_Acquire(netbuff);
+ *
+ * ...
+ *
+ * ccnxCodecNetworkBuffer_Release(&handle);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_Acquire(CCNxCodecNetworkBuffer *original);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] bufferPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * CCNxCodecNetworkBuffer *handle = ccnxCodecNetworkBuffer_Acquire(netbuff);
+ *
+ * ...
+ *
+ * ccnxCodecNetworkBuffer_Release(&handle);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Release(CCNxCodecNetworkBuffer **bufferPtr);
+
+/**
+ * Returns the linearlized cursor position in the buffer.
+ *
+ * Returns the current cursor position in linearized memory location (this does not
+ * actually linearize the memory).
+ *
+ * @param [in] buffer An allocated network buffer.
+ *
+ * @return The linearized memory position (bytes).
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position is 0 since nothing has been written yet
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBuffer_Position(const CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Returns the maximum position to which is written.
+ *
+ * The maximum position of the currently written memory, as if it were linear memory. The limit
+ * will be "0" if no data has been written.
+ *
+ * @param [in] buffer An allocated network buffer.
+ *
+ * @return The lineaized capacity (bytes).
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t limit = ccnxCodecNetworkBuffer_Limit(netbuff);
+ * // limit is msg_length since the buffer was created as a wrapper for the packet_buffer
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Sets the cursor position to the linearized memory location.
+ *
+ * Sets the cursor to the linearized memory location. It must not exceed {@link ccnxCodecNetworkBuffer_Limit}().
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] position The linearized buffer position.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * ccnxCodecNetworkBuffer_SetPosition(netbuff, 1);
+ * // the position is now 1, instead of 0
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_SetPosition(CCNxCodecNetworkBuffer *buffer, size_t position);
+
+/**
+ * Sets the buffer limit to the current position. Throws away anything after.
+ *
+ * The Limit will be set to the current position. Any bytes left after the new Limit are discarded
+ * and un-recoverable. This should be done after finishing writing to the buffer, especially if
+ * the buffer was backed up to discard or overwrite previous data.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint16_t);
+ * ccnxCodecNetworkBuffer_PutUint16(netbuff, 0x1234);
+ * ccnxCodecNetworkBuffer_SetPosition(netbuff, 1);
+ * ccnxCodecNetworkBuffer_Finalize(netbuff);
+ * // the buffer is now only '0x12' and the limit is reduced to 1.
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Finalize(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Writes a `uint8_t` to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value);
+
+/**
+ * Writes a `uint16_t` to the current cursor position, allocating as necessary.
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint16_t);
+ * ccnxCodecNetworkBuffer_PutUint16(netbuff, 0x1234);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint16(CCNxCodecNetworkBuffer *buffer, uint16_t value);
+
+/**
+ * Writes a `uint32_t` to the current cursor position, allocating as necessary.
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint32_t);
+ * ccnxCodecNetworkBuffer_PutUint32(netbuff, 0x12345678);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint32(CCNxCodecNetworkBuffer *buffer, uint32_t value);
+
+/**
+ * Writes a `uint64_t` to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint64_t);
+ * ccnxCodecNetworkBuffer_PutUint64(netbuff, 0x1234567812345678);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint64(CCNxCodecNetworkBuffer *buffer, uint64_t value);
+
+/**
+ * Writes an array to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in array order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] length AThe length of the array to write.
+ * @param [in] array The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * uint8_t array[5] = {1,2,3,4,5};
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + 5;
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, array, 5);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutArray(CCNxCodecNetworkBuffer *buffer, size_t length, const uint8_t *array);
+
+/**
+ * Writes to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in buffer order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + 10;
+ * ccnxCodecNetworkBuffer_PutBuffer(netbuff, buffer);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutBuffer(CCNxCodecNetworkBuffer *buffer, PARCBuffer *value);
+
+/**
+ * Creates a linearized memory buffer.
+ *
+ * Allocates a single buffer and copies the `CCNxCodecNetworkBuffer` to it.
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer`.
+ *
+ * @return non-null A copy of the network buffer's written contents.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * PARCBuffer *buffer = ccnxCodecNetworkBuffer_CreateParcBuffer(netbuff);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecNetworkBuffer_CreateParcBuffer(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Runs a signer over the network buffer
+ *
+ * Runs a {@link PARCSigner} over a specified range of the network buffer
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] start The start position (must be 0 <= start < Limit)
+ * @param [in] end The last posiiton (start < end <= Limit)
+ * @param [in] signer The `PARCSigner`
+ *
+ * @return non-null The {@link PARCSignature} computed by the signer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Init();
+ * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256));
+ *
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * PARCSignature *sig = ccnxCodecNetworkBuffer_ComputeSignature(netbuff, 0, ccnxCodecNetworkBuffer_Limit(netbuff), signer);
+ * }
+ * @endcode
+ */
+PARCSignature *ccnxCodecNetworkBuffer_ComputeSignature(CCNxCodecNetworkBuffer *buffer, size_t start, size_t end, PARCSigner *signer);
+
+/**
+ * Get a `uint8_t` byte from the buffer, does not change position.
+ *
+ * Reads the byte at the given position. The position must be less than the buffer's limit.
+ *
+ * @param [in] netbuff An allocated memory buffer.
+ * @param [in] position Must be 0 <= position < Limit.
+ *
+ * @return number The specified byte
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * uint8_t byte = ccnxCodecNetworkBuffer_GetUint8(netbuff, 0);
+ * }
+ * @endcode
+ */
+uint8_t ccnxCodecNetworkBuffer_GetUint8(const CCNxCodecNetworkBuffer *netbuff, size_t position);
+
+/**
+ * Prints the buffer to the console.
+ *
+ * @param [in] netbuff A `CCNxCodecNetworkBuffer` instance.
+ * @param [in] indent The number of spaces by which to indent the output.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * ccnxCodecNetworkBuffer_Display(netbuff, 0);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Display(const CCNxCodecNetworkBuffer *netbuff, unsigned indent);
+
+// ======================================================================
+// IoVec related
+
+/**
+ * Creates a read-only `CCNxCodecNetworkBufferIoVec` representation of the `CCNxCodecNetworkBuffer`.
+ *
+ * Creates a reference to the `CCNxCodecNetworkBuffer`, so the buffer will not go away until the IoVec is released.
+ * It is a zero-copy operation. The IoVec is a read-only representation. It is used to return a "struct iovec"
+ * for doing a gathering write.
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer` (will acquire a reference to it).
+ *
+ * @return non-null An allocated {@link CCNxCodecNetworkBufferIoVec}, you must call {@link ccnxCodecNetworkBufferIoVec_Release}
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * const struct iovec * iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecNetworkBuffer_CreateIoVec(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Increase the number of references to a `CCNxCodecNetworkBufferIoVec`.
+ *
+ * Note that new `CCNxCodecNetworkBufferIoVec` is not created,
+ * only that the given `CCNxCodecNetworkBufferIoVec` reference count is incremented.
+ * Discard the reference by invoking `ccnxCodecNetworkBufferIoVec_Release`.
+ *
+ * @param [in] vec A pointer to a `CCNxCodecNetworkBufferIoVec` instance to acquire.
+ *
+ * @return The @p vec.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * CCNxCodecNetworkBufferIoVec *handle = ccnxCodecNetworkBufferIoVec_Acquire(vec);
+ * const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(handle);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&handle);
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecNetworkBufferIoVec_Acquire(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] vecPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBufferIoVec_Release(CCNxCodecNetworkBufferIoVec **vecPtr);
+
+/**
+ * Returns the number of extents in the iovec.
+ *
+ * The number of memory buffers gathered in the iovec.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return The number of buffers gathered in the iovec.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * writev(fh, ccnxCodecNetworkBufferIoVec_GetArray(vec), ccnxCodecNetworkBufferIoVec_GetCount(vec));
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+int ccnxCodecNetworkBufferIoVec_GetCount(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Returns an iovec representation of the memory.
+ *
+ * Returns the internal iovec representation of the memory. You do NOT need to free this.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return non-null The internal iovec representation of the memory, do not free
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * writev(fh, ccnxCodecNetworkBufferIoVec_GetArray(vec), ccnxCodecNetworkBufferIoVec_GetCount(vec));
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+const struct iovec *ccnxCodecNetworkBufferIoVec_GetArray(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Dispalys the CCNxCodecNetworkBufferIoVec to the console.
+ *
+ * @param [in] vec A `CCNxCodecNetworkBufferIoVec` instance.
+ * @param [in] indent The number of spaces by which to indent the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBufferIoVec_Display(const CCNxCodecNetworkBufferIoVec *vec, int indent);
+
+/**
+ * The total bytes of all iovecs.
+ *
+ * The total number of bytes as if linearized memory.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return number The total bytes represented by all iovecs
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * size_t interestSize = ccnxCodecNetworkBufferIoVec_Length(vec);
+ * // interestSize will be the size of the linearized interest put into the network buffer
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBufferIoVec_Length(const CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Determine if two `CCNxCodecNetworkBufferIoVec` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxCodecNetworkBufferIoVec` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxCodecNetworkBufferIoVec_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxCodecNetworkBufferIoVec_Equals(x, y)` must return true if and only if
+ * `ccnxCodecNetworkBufferIoVec_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxCodecNetworkBufferIoVec_Equals(x, y)` returns true and
+ * `ccnxCodecNetworkBufferIoVec_Equals(y, z)` returns true,
+ * then `ccnxCodecNetworkBufferIoVec_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxCodecNetworkBufferIoVec_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxCodecNetworkBufferIoVec_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] a A pointer to a `CCNxCodecNetworkBufferIoVec` instance.
+ * @param [in] b A pointer to a `CCNxCodecNetworkBufferIoVec` instance.
+ *
+ * @return true if `CCNxCodecNetworkBufferIoVec` x and y are equal.
+ * @return false if `CCNxCodecNetworkBufferIoVec` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec1 = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * CCNxCodecNetworkBufferIoVec *vec2 = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * if (ccnxCodecNetworkBufferIoVec_Equals(vec1, vec2)) {
+ * printf("IOVectors are equal.\n");
+ * } else {
+ * printf("IOVectors are NOT equal.\n");
+ * }
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+bool ccnxCodecNetworkBufferIoVec_Equals(const CCNxCodecNetworkBufferIoVec *a, const CCNxCodecNetworkBufferIoVec *b);
+#endif // Libccnx_codec_ccnxCodecNetworkBuffer_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c
new file mode 100755
index 00000000..8e547743
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+
+/**
+ * We use a 2-byte T and a 2-byte L
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+struct ccnx_codec_tlv_decoder {
+ // we use a read only buffer because we want independent
+ // position and limit from whatever the user gives us.
+ PARCBuffer *buffer;
+
+ CCNxCodecError *error;
+};
+
+CCNxCodecTlvDecoder *
+ccnxCodecTlvDecoder_Create(PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ CCNxCodecTlvDecoder *decoder = parcMemory_AllocateAndClear(sizeof(CCNxCodecTlvDecoder));
+ assertNotNull(decoder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecTlvDecoder));
+
+ // create a reference but with independent position + limit from what the user gives us
+ decoder->buffer = parcBuffer_Slice(buffer);
+
+ return decoder;
+}
+
+void
+ccnxCodecTlvDecoder_Destroy(CCNxCodecTlvDecoder **decoderPtr)
+{
+ assertNotNull(decoderPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*decoderPtr, "Parameter must dereferecne to non-null pointer");
+ CCNxCodecTlvDecoder *decoder = *decoderPtr;
+ parcBuffer_Release(&decoder->buffer);
+
+
+ if (decoder->error) {
+ ccnxCodecError_Release(&decoder->error);
+ }
+
+ parcMemory_Deallocate((void **) &decoder);
+ *decoderPtr = NULL;
+}
+
+bool
+ccnxCodecTlvDecoder_IsEmpty(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return (!parcBuffer_HasRemaining(decoder->buffer));
+}
+
+bool
+ccnxCodecTlvDecoder_EnsureRemaining(CCNxCodecTlvDecoder *decoder, size_t bytes)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Remaining(decoder->buffer) >= bytes;
+}
+
+size_t
+ccnxCodecTlvDecoder_Remaining(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Remaining(decoder->buffer);
+}
+
+uint16_t
+ccnxCodecTlvDecoder_PeekType(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ size_t position = parcBuffer_Position(decoder->buffer);
+ uint16_t type = parcBuffer_GetUint16(decoder->buffer);
+ parcBuffer_SetPosition(decoder->buffer, position);
+ return type;
+}
+
+uint16_t
+ccnxCodecTlvDecoder_GetType(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_GetUint16(decoder->buffer);
+}
+
+uint16_t
+ccnxCodecTlvDecoder_GetLength(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_GetUint16(decoder->buffer);
+}
+
+PARCBuffer *
+ccnxCodecTlvDecoder_GetValue(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ PARCBuffer *value = NULL;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ value = parcBuffer_Slice(decoder->buffer);
+ parcBuffer_SetLimit(value, length);
+
+ size_t position = parcBuffer_Position(decoder->buffer);
+ position += length;
+ parcBuffer_SetPosition(decoder->buffer, position);
+ }
+
+ return value;
+}
+
+PARCBuffer *
+ccnxCodecTlvDecoder_GetBuffer(CCNxCodecTlvDecoder *decoder, uint16_t type)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+
+ PARCBuffer *output = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+ output = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ }
+ }
+ return output;
+}
+
+CCNxCodecTlvDecoder *
+ccnxCodecTlvDecoder_GetContainer(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ CCNxCodecTlvDecoder *innerDecoder = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ innerDecoder = ccnxCodecTlvDecoder_Create(value);
+ parcBuffer_Release(&value);
+ }
+ return innerDecoder;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint8(CCNxCodecTlvDecoder *decoder, uint16_t type, uint8_t *output)
+{
+ const size_t valueLength = 1;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint8(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint16(CCNxCodecTlvDecoder *decoder, uint16_t type, uint16_t *output)
+{
+ const size_t valueLength = 2;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint16(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint32(CCNxCodecTlvDecoder *decoder, uint16_t type, uint32_t *output)
+{
+ const size_t valueLength = 4;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint32(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint64(CCNxCodecTlvDecoder *decoder, uint16_t type, uint64_t *output)
+{
+ const size_t valueLength = 8;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint64(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+
+size_t
+ccnxCodecTlvDecoder_Position(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Position(decoder->buffer);
+}
+
+bool
+ccnxCodecTlvDecoder_Advance(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= length) {
+ size_t position = parcBuffer_Position(decoder->buffer);
+ position += length;
+ parcBuffer_SetPosition(decoder->buffer, position);
+ success = true;
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_BufferToVarInt(PARCBuffer *buffer, uint16_t length, uint64_t *output)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ bool success = false;
+ if (length >= 1 && length <= 8 && parcBuffer_Remaining(buffer) >= length) {
+ uint64_t value = 0;
+ for (int i = 0; i < length; i++) {
+ value = value << 8 | parcBuffer_GetUint8(buffer);
+ }
+ *output = value;
+ success = true;
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetVarInt(CCNxCodecTlvDecoder *decoder, uint16_t length, uint64_t *output)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return ccnxCodecTlvDecoder_BufferToVarInt(decoder->buffer, length, output);
+}
+
+bool
+ccnxCodecTlvDecoder_HasError(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (decoder->error) {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool
+ccnxCodecTlvDecoder_SetError(CCNxCodecTlvDecoder *decoder, CCNxCodecError *error)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (ccnxCodecTlvDecoder_HasError(decoder)) {
+ return false;
+ }
+
+ decoder->error = ccnxCodecError_Acquire(error);
+ return true;
+}
+
+
+void
+ccnxCodecTlvDecoder_ClearError(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (ccnxCodecTlvDecoder_HasError(decoder)) {
+ ccnxCodecError_Release(&decoder->error);
+ }
+}
+
+
+CCNxCodecError *
+ccnxCodecTlvDecoder_GetError(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return decoder->error;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h
new file mode 100755
index 00000000..39cdcb94
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h
@@ -0,0 +1,677 @@
+/*
+ * 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_TlvDecoder.h
+ * @ingroup networking
+ * @brief TLV codec for messages
+ *
+ * TLV decoder
+ *
+ * Terminology:
+ * type = a field that labels a value
+ * length = the byte lenth of the value
+ * value = the data
+ * header = type + length
+ * container= a value that contains TLVs
+ *
+ * For example, in this structure, the "type 1" TLV is a container that holds a second TLV
+ * The second TLV is a terminal, and holds an opaque value.
+ *
+ * { .type = 1, .length = 20, .value = { .type = 2, .length = 16, .value ="It was a dark a " } }
+ *
+ * To decode the above example, we would use the decoder like this:
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 3) {
+ * size_t end = ccnxCodecTlvDecoder_GetPosition(decoder) + length;
+ * while ( ccnxCodecTlvDecoder_GetPosition(decoder) < end ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ * Another way to do the same parsing without having to use `ccnxCodecTlvDecoder_GetPosition' is to
+ * recursively parse each value:
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * if (type == 3) {
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_Create(value);
+ * while ( ! ccnxCodecTlvDecoder_IsEmpty(innerDecoder) ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ * And an even cleaner way is to use ccnxCodecTlvDecoder_GetContainer to pull out sub-decoders
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 3) {
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, length);
+ * while ( ! ccnxCodecTlvDecoder_IsEmpty(innerDecoder) ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvDecoder_h
+#define libccnx_ccnx_TlvDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Signature.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+
+struct ccnx_codec_tlv_decoder;
+typedef struct ccnx_codec_tlv_decoder CCNxCodecTlvDecoder;
+
+/**
+ * Decodes a TLV-encoded buffer to individual buffers for each Value
+ *
+ * Walks through a TLV-encoded buffer returning buffer slices of the
+ * original. These are 0-copy operations.
+ *
+ * The decoder should be based on the CCNxCodecNetworkBufferIoVec, see case 1009
+ *
+ * @param [in] buffer The buffer to parse, must be ready to read.
+ *
+ * @return non-null A TLV decoder
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * }
+ * @endcode
+ */
+CCNxCodecTlvDecoder *ccnxCodecTlvDecoder_Create(PARCBuffer *buffer);
+
+/**
+ * Releases the tlv decoder.
+ *
+ * Buffers that have been previously returned remain acquired. The internal
+ * reference to the input buffer will be released.
+ *
+ * @param [in] decoderPtr Pointer to the decoder to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvDecoder_Destroy(CCNxCodecTlvDecoder **decoderPtr);
+
+/**
+ * Tests if there is anything left to decode
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true There are more bytes available
+ * @return false At the end of the buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_IsEmpty(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Checks if there are at least `bytes' bytes remaining in the buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true There are at least `bytes' bytes left
+ * @return false Buffer underrun
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_EnsureRemaining(CCNxCodecTlvDecoder *decoder, size_t bytes);
+
+/**
+ * Returns the bytes remaining in the decoder
+ *
+ * The remaining bytes to be decoded
+ *
+ * @param [in] decoder An allocated decoder
+ *
+ * @retval number The bytes left to decode
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvDecoder_Remaining(const CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Gets the next bytes as the TLV type
+ *
+ * The buffer is advanced the width of the type
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_GetType(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Returns the TLV Type but does not advance the decoder
+ *
+ * At the current position, decode the next bytes as the TLV type
+ *
+ * @param [in] decoder The Decoder object
+ *
+ * @return number The TLV type
+ *
+ * Example:
+ * @code
+ * {
+ * // PeekType |--------|
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_PeekType(decoder);
+ * if( type == 0xAABB ) {
+ * (void) ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_PeekType(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Gets the next bytes as the TLV length
+ *
+ * The buffer is advanced the width of the length
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_GetLength(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Returns the next `length' bytes as a value
+ *
+ * The buffer is advanced `length' bytes. The returned value is ready for reading.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvDecoder_GetValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Ensure the current position is of type `type', then return a buffer of the value
+ *
+ * If the buffer points to a type of `type', the function will create a buffer of
+ * the specified length and return the value in a buffer.
+ *
+ * The function will return NULL if the types don't match or if there is a
+ * a decoder underrun (its not as long as the type specifies), or if the length would
+ * take the end of the input buffer.
+ *
+ * @param [in] decoder The TLV decoder object
+ * @param [in] type The type type to validate
+ *
+ * @return non-null A conforming buffer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * // GetBuffer |--------------------------------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ *
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ *
+ * PARCBuffer *buffer = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ * // buffer contains { 0x01, 0x02, 0x03, 0x04 }
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvDecoder_GetBuffer(CCNxCodecTlvDecoder *decoder, uint16_t type);
+
+/**
+ * The current location is a TLV container (a value that is TLVs)
+ *
+ * Returns a TLV decoder that represents the "slice" of the input buffer from
+ * the current position up to the current position plus `length'.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A new sub-decoder
+ * @return null An error, such as input underrun
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetContainer |--------------------------------------------|
+ * // GetBuffer |--------------------------------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 12, 0, 12);
+ *
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ *
+ * uint16_t containerType = ccnxCodecTlvDecoder_GetType(decoder);
+ * size_t containerLength = ccnxCodecTlvDecoder_GetLength(decoder);
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, containerLength);
+ * PARCBuffer *buffer = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ *
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ *
+ * // buffer contains { 0x01, 0x02, 0x03, 0x04 }
+ * }
+ * @endcode
+ */
+CCNxCodecTlvDecoder *ccnxCodecTlvDecoder_GetContainer(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Decodes the current location as a type, length, and uint8_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint8_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "1", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint8_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ * assert(success && value == 0xFF);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint8(CCNxCodecTlvDecoder *decoder, uint16_t type, uint8_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint16_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint16_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "2", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0xAA }, 6, 0, 6 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint16_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ * assert(success && value == 0xFFAA);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint16(CCNxCodecTlvDecoder *decoder, uint16_t type, uint16_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint32_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint32_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "4", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0xAA, 0xBB, 0xCC }, 8, 0, 8 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint32_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ * assert(success && value == 0xFFAABBCC);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint32(CCNxCodecTlvDecoder *decoder, uint16_t type, uint32_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint64_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint64_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "8", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0xAA, 0xBB, 0xCC, 0x00, 0x00, 0x00, 0x00 }, 12, 0, 12 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint64_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ * assert(success && value == 0xFFAABBCC00000000ULL);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint64(CCNxCodecTlvDecoder *decoder, uint16_t type, uint64_t *output);
+
+/**
+ * Returns the current byte position of the buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvDecoder_Position(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Advance the decoder a given number of bytes
+ *
+ * Advance the decoder, throwing away a given number of bytes.
+ * If there are not enough bytes left in the decoder, no action is taken
+ *
+ * @param [in] decoder The decoder to advance
+ * @param [in] length The number of bytes to skip
+ *
+ * @return true Advanced the buffer
+ * @return false Error, likely a buffer underrun (not enough bytes)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_Advance(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Decode the current position as a VarInt
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order.
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] length The number of bytes in the varint
+ * @param [out] output The value of the varint
+ *
+ * @return true Successful decode
+ * @return fale Error (length too long, too short, or not enough bytes in decoder)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint64_t value;
+ * ccnxCodecTlvDecoder_GetVarInt(decoder, 3, &value);
+ * // value = 0x0000000000102300
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetVarInt(CCNxCodecTlvDecoder *decoder, uint16_t length, uint64_t *output);
+
+
+/**
+ * Decode the current position of the Buffer as a VarInt out to 'length' bytes
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order. The buffer must have at least 'length' bytes remaining.
+ * The buffer is advanced.
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] length The number of bytes in the varint
+ * @param [out] output The value of the varint
+ *
+ * @return true Successful decode
+ * @return fale Error (length too long, too short, or not enough bytes in decoder)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 );
+ * uint64_t value;
+ * ccnxCodecTlvDecoder_BufferToVarInt(buffer, 3, &value);
+ * // value = 0x0000000000102300
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_BufferToVarInt(PARCBuffer *buffer, uint16_t length, uint64_t *output);
+
+/**
+ * Determines if the TLV Encoder has an error condition set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_HasError(const CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Sets an error condition. Only one error condition may be set.
+ *
+ * Stores a reference counted copy of the CCNxCodecError. If an error is already set,
+ * this function returns false and does not store a reference count. The previous error
+ * stays as the current error.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Error condition set
+ * @return false Error already set, you must clear it first
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_SetError(CCNxCodecTlvDecoder *decoder, CCNxCodecError *error);
+
+/**
+ * Clears the error condition, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvDecoder_ClearError(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Retrieves the error message
+ *
+ * Retrieves the error condition, if any. If no error is set, will return NULL.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The error condition set
+ * @return null No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecTlvDecoder_GetError(const CCNxCodecTlvDecoder *encoder);
+#endif // libccnx_ccnx_TlvDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c
new file mode 100755
index 00000000..bfc52234
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+/**
+ * We use a 2-byte T and a 2-byte L
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+#define NONE_SET 0
+#define START_SET 1
+#define END_SET 2
+#define BOTH_SET 3
+
+struct ccnx_codec_tlv_encoder {
+ CCNxCodecNetworkBuffer *buffer;
+
+ // OR of NONE_SET, START_SET, END_SET
+ int signatureStartEndSet;
+
+ size_t signatureStart;
+ size_t signatureEnd;
+
+ CCNxCodecError *error;
+ PARCSigner *signer;
+};
+
+CCNxCodecTlvEncoder *
+ccnxCodecTlvEncoder_Create(void)
+{
+ CCNxCodecTlvEncoder *encoder = parcMemory_AllocateAndClear(sizeof(CCNxCodecTlvEncoder));
+ assertNotNull(encoder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecTlvEncoder));
+
+ encoder->buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ encoder->signatureStartEndSet = NONE_SET;
+ encoder->error = NULL;
+
+ return encoder;
+}
+
+void
+ccnxCodecTlvEncoder_Destroy(CCNxCodecTlvEncoder **encoderPtr)
+{
+ assertNotNull(encoderPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*encoderPtr, "Parameter must dereferecne to non-null pointer");
+ CCNxCodecTlvEncoder *encoder = *encoderPtr;
+
+ ccnxCodecNetworkBuffer_Release(&encoder->buffer);
+
+ if (encoder->error) {
+ ccnxCodecError_Release(&encoder->error);
+ }
+
+ if (encoder->signer) {
+ parcSigner_Release(&encoder->signer);
+ }
+
+ parcMemory_Deallocate((void **) &encoder);
+ *encoderPtr = NULL;
+}
+
+CCNxCodecTlvEncoder *
+ccnxCodecTlvEncoder_Initialize(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendBuffer(CCNxCodecTlvEncoder *encoder, uint16_t type, PARCBuffer *value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(parcBuffer_Remaining(value) <= UINT16_MAX, "Value length too long, got %zu maximum %u\n", parcBuffer_Remaining(value), UINT16_MAX);
+
+ size_t bytes = 4 + parcBuffer_Remaining(value);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, parcBuffer_Remaining(value));
+ ccnxCodecNetworkBuffer_PutBuffer(encoder->buffer, value);
+
+ return bytes;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendArray(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length, const uint8_t array[length])
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+ ccnxCodecNetworkBuffer_PutArray(encoder->buffer, length, array);
+ return length + 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendContainer(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+ return 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint8(CCNxCodecTlvEncoder *encoder, uint16_t type, uint8_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 1);
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, value);
+ return 5;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint16(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 2);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, value);
+ return 6;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint32(CCNxCodecTlvEncoder *encoder, uint16_t type, uint32_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 4);
+ ccnxCodecNetworkBuffer_PutUint32(encoder->buffer, value);
+ return 8;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint64(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 8);
+ ccnxCodecNetworkBuffer_PutUint64(encoder->buffer, value);
+ return 12;
+}
+
+static unsigned
+_ccnxCodecTlvEncoder_ComputeVarIntLength(uint64_t value)
+{
+ unsigned length = 8;
+ if (value <= 0x00000000000000FFULL) {
+ length = 1;
+ } else if (value <= 0x000000000000FFFFULL) {
+ length = 2;
+ } else if (value <= 0x0000000000FFFFFFULL) {
+ length = 3;
+ } else if (value <= 0x00000000FFFFFFFFULL) {
+ length = 4;
+ } else if (value <= 0x000000FFFFFFFFFFULL) {
+ length = 5;
+ } else if (value <= 0x0000FFFFFFFFFFFFULL) {
+ length = 6;
+ } else if (value <= 0x00FFFFFFFFFFFFFFULL) {
+ length = 7;
+ }
+
+ return length;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendVarInt(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ unsigned length = _ccnxCodecTlvEncoder_ComputeVarIntLength(value);
+
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+
+ // See case 1007
+ bool mustContinue = false;
+ for (int byte = 7; byte >= 0; byte--) {
+ uint8_t b = (value >> (byte * 8)) & 0xFF;
+ if (b != 0 || byte == 0 || mustContinue) {
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, b);
+ mustContinue = true;
+ }
+ }
+
+ return length + 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_Position(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return ccnxCodecNetworkBuffer_Position(encoder->buffer);
+}
+
+size_t
+ccnxCodecTlvEncoder_SetPosition(CCNxCodecTlvEncoder *encoder, size_t position)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(position <= ccnxCodecNetworkBuffer_Limit(encoder->buffer),
+ "position beyond end of buffer, got %zu maximum %zu",
+ position, ccnxCodecNetworkBuffer_Limit(encoder->buffer));
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return position;
+}
+
+void
+ccnxCodecTlvEncoder_SetContainerLength(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t length)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ size_t currentPosition = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+
+ // +2 because we skip over the Type field
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset + 2);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, currentPosition);
+}
+
+void
+ccnxCodecTlvEncoder_Finalize(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ // set the limit to whatever our current possition is. That will truncate the
+ // packet in case we wrote beyond where we are now.
+
+ ccnxCodecNetworkBuffer_Finalize(encoder->buffer);
+}
+
+PARCBuffer *
+ccnxCodecTlvEncoder_CreateBuffer(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ PARCBuffer *output = ccnxCodecNetworkBuffer_CreateParcBuffer(encoder->buffer);
+ return output;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecTlvEncoder_CreateIoVec(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return ccnxCodecNetworkBuffer_CreateIoVec(encoder->buffer);
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendRawArray(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t array[length])
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutArray(encoder->buffer, length, array);
+ return length;
+}
+
+size_t
+ccnxCodecTlvEncoder_PutUint8(CCNxCodecTlvEncoder *encoder, size_t offset, uint8_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ size_t position = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset);
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, value);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return 1;
+}
+
+size_t
+ccnxCodecTlvEncoder_PutUint16(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ size_t position = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, value);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return 2;
+}
+
+void
+ccnxCodecTlvEncoder_MarkSignatureStart(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ encoder->signatureStart = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ encoder->signatureStartEndSet |= START_SET;
+}
+
+void
+ccnxCodecTlvEncoder_MarkSignatureEnd(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ encoder->signatureEnd = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ encoder->signatureStartEndSet |= END_SET;
+}
+
+PARCSignature *
+ccnxCodecTlvEncoder_ComputeSignature(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(encoder->signatureStartEndSet == BOTH_SET, "Did not set both start and end positions");
+
+ return ccnxCodecNetworkBuffer_ComputeSignature(encoder->buffer, encoder->signatureStart, encoder->signatureEnd, encoder->signer);
+}
+
+bool
+ccnxCodecTlvEncoder_HasError(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ if (encoder->error) {
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ccnxCodecTlvEncoder_SetError(CCNxCodecTlvEncoder *encoder, CCNxCodecError *error)
+{
+ if (ccnxCodecTlvEncoder_HasError(encoder)) {
+ return false;
+ }
+
+ encoder->error = ccnxCodecError_Acquire(error);
+ return true;
+}
+
+void
+ccnxCodecTlvEncoder_ClearError(CCNxCodecTlvEncoder *encoder)
+{
+ if (ccnxCodecTlvEncoder_HasError(encoder)) {
+ ccnxCodecError_Release(&encoder->error);
+ }
+}
+
+CCNxCodecError *
+ccnxCodecTlvEncoder_GetError(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder->error;
+}
+
+void
+ccnxCodecTlvEncoder_SetSigner(CCNxCodecTlvEncoder *encoder, PARCSigner *signer)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ if (encoder->signer) {
+ parcSigner_Release(&encoder->signer);
+ }
+
+ if (signer) {
+ encoder->signer = parcSigner_Acquire(signer);
+ } else {
+ encoder->signer = NULL;
+ }
+}
+
+PARCSigner *
+ccnxCodecTlvEncoder_GetSigner(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder->signer;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h
new file mode 100644
index 00000000..443eeca0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h
@@ -0,0 +1,755 @@
+/*
+ * 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_TlvEncoder.h
+ * @ingroup networking
+ * @brief TLV codec for messages
+ *
+ * TLV encoder
+ *
+ * Terminology:
+ * type = a field that labels a value
+ * length = the byte lenth of the value
+ * value = the data
+ * header = type + length
+ * container= a value that contains TLVs
+ *
+ * For example, in this structure, the "type 1" TLV is a container that holds a second TLV
+ * The second TLV is a terminal, and holds an opaque value.
+ *
+ * { .type = 1, .length = 20, .value = { .type = 2, .length = 16, .value ="It was a dark a " } }
+ *
+ * Example to encode a container that wraps a name and an address:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *nameAndAddress = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ *
+ * // Initialize starts a new buffer
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 3, nameAndAddress);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ *
+ * parcBuffer_Destroy(&nameAndAddress);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ *
+ * // now use the container for something...
+ * }
+ * @endcode
+ *
+ * The TLV will look something like this:
+ * @code
+ * { .type = 3, .length = L1 + L2 + overhead, .value = {
+ * {.type = 1, .length = L1, .value = name},
+ * {.type = 2, .length = L2, .value = address}
+ * }
+ * }
+ * @endcode
+ *
+ * An alternative way to encode it that does not require recursive encoder is to use Position:
+ * @code
+ * {
+ * // Creates {{T=3, L=length, V={{T=1, L=..., V=name}, {T=2, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 3, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 1, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvEncoder_h
+#define libccnx_ccnx_TlvEncoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Signature.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+// ======================================================
+
+struct ccnx_codec_tlv_encoder;
+typedef struct ccnx_codec_tlv_encoder CCNxCodecTlvEncoder;
+
+/**
+ * Creates a TLV encoder
+ *
+ * The encoder is re-usable, as the state is reset for each Initialize.
+ *
+ * @return non-null A TLV encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecTlvEncoder *ccnxCodecTlvEncoder_Create(void);
+
+/**
+ * Destroys the TLV encoder and all internal state
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_Destroy(CCNxCodecTlvEncoder **encoderPtr);
+
+/**
+ * Initialize the encoder to start a new encoding
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] tlv <#description#>
+ *
+ * @return non-null The encoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+CCNxCodecTlvEncoder *ccnxCodecTlvEncoder_Initialize(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Appends a TL container and a PARCBuffer to the enoder
+ *
+ * The type is from the parameter `type', the length is from the remaining size
+ * of the value buffer, and the value comes from `value'.
+ *
+ * @param [in] encoder The encoder to append to
+ * @param [in] type The TLV type
+ * @param [in] value The length is the remaining buffer size, the position is advanced.
+ *
+ * @return number The total bytes of the TLV, including the T and L.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendBuffer(CCNxCodecTlvEncoder *encoder, uint16_t type, PARCBuffer *value);
+
+/**
+ * Appends a "TL" container then the bytes of the array
+ *
+ * Writes a Type of 'type' and Length of 'length' then appends 'length' bytes from
+ * the array to the encoder.
+ *
+ * @param [in] encoder An allocated CCnxCodecTlvEncoder
+ * @param [in] type The TLV type
+ * @param [in] length The TLV length
+ * @param [in] array The bytes to append
+ *
+ * @return number The number of bytes appended (including the T and L)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendArray(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length, const uint8_t *array);
+
+/**
+ * Appends a TL without a V.
+ *
+ * Appends a T and L without a V. Useful for doing a heirarchical encoding where the V
+ * will be more TLVs. You will either need to know L or go back and fix it up.
+ *
+ * @param [in] encoder The encoder to modify
+ * @param [in] type The TLV type
+ * @param [in] length The TLV length, use 0 if you do not know.
+ *
+ * @return bytes The bytes appended (the size of the T and L)
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendContainer(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length);
+
+/**
+ * Adds a TLV with an 8-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (5)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 1, .value = 0x19 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint8(encoder, 1, (uint8_t) 25);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint8(CCNxCodecTlvEncoder *encoder, uint16_t type, uint8_t value);
+
+/**
+ * Adds a TLV with a 16-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (6)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 2, .value = 0x1234 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint16(encoder, 1, (uint16_t) 0x1234);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint16(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t value);
+
+/**
+ * Adds a TLV with a 32-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (8)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 4, .value = 0x12345678 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint32(encoder, 1, (uint32_t) 0x12345678);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint32(CCNxCodecTlvEncoder *encoder, uint16_t type, uint32_t value);
+
+
+/**
+ * Adds a TLV with a 64-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (8)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 8, .value = 0x0000000012345678 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint64(encoder, 1, (uint64_t) 0x12345678);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint64(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value);
+
+/**
+ * Returns the current encoding buffer position
+ *
+ * This is useful if you need to backtrack to fill in a length you did not know before.
+ *
+ * @param [in] encoder The Tlv encoder object
+ *
+ * @return number The byte offset of the encode buffer
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_Position(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Used to rewind and erase
+ *
+ * For example, you called ccnxCodecTlvEncoder_AppendContainer() then found out that
+ * the container was empty. If you rewind to just before you added the container, it
+ * is as if the container were never added.
+ *
+ * @param [in] position Must be no more than ccnxCodecTlvEncoder_Position()
+ *
+ * @return number The position after calling SetPosition
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_SetPosition(CCNxCodecTlvEncoder *encoder, size_t position);
+
+/**
+ * Sets the length field of the container at the given offset
+ *
+ * User `ccnxCodecTlvEncoder_Position' before `ccnxCodecTlvEncoder_AppendContainer' to get the container's
+ * offset. You can then set that container's length with this function.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] offset position of the container in the Tlv Encoder
+ * @param [in] length The container length to set
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_SetContainerLength(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t length);
+
+/**
+ * Finalizes the encoding and returns the encoded buffer
+ *
+ * The buffer is ready for reading. In specific, it will truncate the buffer at the
+ * current position, setting the Limit to that location. This will cut off any
+ * writes to the buffer that have been "erased" by setting the position to an
+ * earlier location.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_Finalize(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Creates a PARCBuffer from position 0 to the Limit.
+ *
+ * Returns a PARCBuffer from position 0 to the Limit. If the user has called
+ * ccnxCodecTlvEncoder_SetPosition() to rewind the buffer, the user should likely call
+ * ccnxCodecTlvEncoder_Finalize() to trim the Limit, otherwise there may be unexpected
+ * bytes at the end.
+ *
+ * The PARCBuffer representation is not the native form of the buffer and will result
+ * in a deep copy of the buffer.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null An allocated PARCBuffer, use parcBuffer_Release() on it
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvEncoder_CreateBuffer(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Creates a vectored I/O representation of the encoder
+ *
+ * Returns a CCNxCodecNetworkBufferIoVec from position 0 to the Limit. If the user has called
+ * ccnxCodecTlvEncoder_SetPosition() to rewind the buffer, the user should likely call
+ * ccnxCodecTlvEncoder_Finalize() to trim the Limit, otherwise there may be unexpected
+ * bytes at the end.
+ *
+ * The CCNxCodecNetworkBufferIoVec is the native form of the memory and does not involve any copies.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null An allocated CCNxCodecNetworkBufferIoVec, use CCNxCodecNetworkBufferIoVec_Release() on it
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecTlvEncoder_CreateIoVec(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Marks the current position as the start of the signature
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder, signer);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_MarkSignatureStart(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Marks the current position as the end (non-inclusive) of the Signature
+ * Example:
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder, signer);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_MarkSignatureEnd(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Computes the cryptographic signature over the designated area.
+ * If both a Start and End have not been set, function will assert
+ *
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @retval non-null An allocated PARCSignature
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * ccnxCodecTlvEncoder_SetSigner(signer);
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+PARCSignature *ccnxCodecTlvEncoder_ComputeSignature(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Puts a uint8_t at the specified position.
+ *
+ * Does not modify the current position of the Tlv Encoder
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return number The number of bytes put
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_PutUint8(CCNxCodecTlvEncoder *encoder, size_t offset, uint8_t value);
+
+/**
+ * Puts a uint16_t at the specified position.
+ *
+ * Does not modify the current position of the Tlv Encoder
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return number The number of bytes put
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_PutUint16(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t value);
+
+/**
+ * Writes an array to the current position. No "TL" container is written.
+ *
+ * Unlike ccnxCodecTlvEncoder_AppendArray, this does not append a Type and Length container for the array.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] length The number of bytes from array to write
+ * @param [in] array The source array
+ *
+ * @return number The number of bytes appended to the encoder
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendRawArray(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t *array);
+
+
+/**
+ * Determines if the TLV Encoder has an error condition set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @retval true An error condition is set
+ * @retval false No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvEncoder_HasError(const CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Sets an error condition. Only one error condition may be set.
+ *
+ * Stores a reference counted copy of the CCNxCodecError. If an error is already set,
+ * this function returns false and does not store a reference to the error. The previous error
+ * stays as the current error.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return true Error condition set
+ * @return false Error already set, you must clear it first
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvEncoder_SetError(CCNxCodecTlvEncoder *encoder, CCNxCodecError *error);
+
+/**
+ * Clears the error condition, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_ClearError(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Retrieves the error message
+ *
+ * Retrieves the error condition, if any. If no error is set, will return NULL.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null The error condition set
+ * @return null No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecTlvEncoder_GetError(const CCNxCodecTlvEncoder *encoder);
+
+
+/**
+ * Associates a signer with the encoder for producing signatures or MACs
+ *
+ * Stores a reference counted copy of the signer. The reference will be released with the
+ * CCNxCodecTlvEncoder is released or if this function is called multiple times.
+ *
+ * It is allowed to set a NULL singer.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] singer Assocaited a PARCSigner with the encoder, storing a reference to it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_SetSigner(CCNxCodecTlvEncoder *encoder, PARCSigner *signer);
+
+/**
+ * Returns the PARCSigner associated with the encoder, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null The signer assocated with the encoder
+ * @return null There is no singer associated with the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSigner *ccnxCodecTlvEncoder_GetSigner(const CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Appends a TLV container holding the value as a VarInt
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order. The value of "0" is encoded as a single
+ * byte of "0".
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value of the varint
+ *
+ * @return number The number of bytes appended
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t value = 0x0000000000102300
+ * size_t length = ccnxCodecTlvEncoder_AppendVarInt(encoder, 12, value);
+ * // length = 7
+ * // appedned { 0x00, 0x0C, 0x00, 0x03, 0x10, 0x23, 0x00 }
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendVarInt(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value);
+
+#endif // libccnx_ccnx_TlvEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c
new file mode 100755
index 00000000..9df01867
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c
@@ -0,0 +1,190 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+#include <arpa/inet.h>
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+static CCNxTlvDictionary *
+_decodeV1(PARCBuffer *packetBuffer)
+{
+ CCNxTlvDictionary *packetDictionary = NULL;
+
+ CCNxCodecSchemaV1Types_PacketType packetType = (CCNxCodecSchemaV1Types_PacketType) parcBuffer_GetAtIndex(packetBuffer, 1);
+
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ // not implemented yet
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_Control:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ break;
+
+ default:
+ // unknown type
+ break;
+ }
+
+ if (packetDictionary) {
+ // The packetBuffer may be padded or have extraneous content after the CCNx message.
+ // Ensure that the buffer limit reflects the CCNx packet length as the decoder uses
+ // the that limit, not the packetLength from the header, to determine when to stop parsing.
+ size_t packetBufferLength = ccnxCodecTlvPacket_GetPacketLength(packetBuffer);
+ assertTrue(packetBufferLength <= parcBuffer_Remaining(packetBuffer), "Short packet buffer");
+ parcBuffer_SetLimit(packetBuffer, packetBufferLength);
+ bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, packetDictionary);
+ if (!success) {
+ ccnxTlvDictionary_Release(&packetDictionary);
+ }
+ }
+ return packetDictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecTlvPacket_Decode(PARCBuffer *packetBuffer)
+{
+ return _decodeV1(packetBuffer);
+}
+
+bool
+ccnxCodecTlvPacket_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary)
+{
+ // Determine the version from the first byte of the buffer
+ uint8_t version = parcBuffer_GetAtIndex(packetBuffer, 0);
+
+ // The packetBuffer may be padded or have extraneous content after the CCNx message.
+ // Ensure that the buffer limit reflects the CCNx packet length as the decoder uses
+ // the that limit, not the packetLength from the header, to determine when to stop parsing.
+ size_t packetBufferLength = ccnxCodecTlvPacket_GetPacketLength(packetBuffer);
+ assertTrue(packetBufferLength <= parcBuffer_Remaining(packetBuffer), "Short packet buffer");
+ parcBuffer_SetLimit(packetBuffer, packetBufferLength);
+
+ bool success = false;
+ switch (version) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, packetDictionary);
+ break;
+
+ default:
+ // will return false
+ break;
+ }
+
+ return success;
+}
+
+/*
+ * We don't have an iovec based decoder yet, so linearize the memory and use a PARCBuffer
+ * See case 903.
+ */
+bool
+ccnxCodecTlvPacket_IoVecDecode(CCNxCodecNetworkBufferIoVec *vec, CCNxTlvDictionary *packetDictionary)
+{
+ size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ PARCBuffer *buffer = NULL;
+ if (iovcnt == 1) {
+ buffer = parcBuffer_Wrap(array[0].iov_base, array[0].iov_len, 0, array[0].iov_len);
+ } else if (iovcnt > 1) {
+ // figure out total size, then linearize it
+ size_t totalbytes = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ totalbytes += array[i].iov_len;
+ }
+
+ buffer = parcBuffer_Allocate(totalbytes);
+ for (int i = 0; i < iovcnt; i++) {
+ parcBuffer_PutArray(buffer, array[i].iov_len, array[i].iov_base);
+ }
+
+ parcBuffer_Flip(buffer);
+ } else {
+ return false;
+ }
+
+ bool success = ccnxCodecTlvPacket_BufferDecode(buffer, packetDictionary);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecTlvPacket_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer)
+{
+ CCNxTlvDictionary_SchemaVersion version = ccnxTlvDictionary_GetSchemaVersion(packetDictionary);
+
+ CCNxCodecNetworkBufferIoVec *iovec = NULL;
+ switch (version) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(packetDictionary, signer);
+ break;
+
+ default:
+ // will return NULL
+ break;
+ }
+ return iovec;
+}
+
+size_t
+ccnxCodecTlvPacket_GetPacketLength(PARCBuffer *packetBuffer)
+{
+ size_t length = 0;
+
+ // Determine the version from the first byte of the buffer
+ uint8_t *header = parcBuffer_Overlay(packetBuffer, 0);
+
+ switch (header[0]) {
+ case CCNxTlvDictionary_SchemaVersion_V1: { // V1 - from metis_TlvSchemaV1.c:_totalPacketLength
+ CCNxCodecSchemaV1FixedHeader *headerV1 = (CCNxCodecSchemaV1FixedHeader *) header;
+ length = htons(headerV1->packetLength);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return length;
+}
+
+// When new versions are created they need to be incorporated here so enough header information
+// can be read to determine how to proceed.
+size_t
+ccnxCodecTlvPacket_MinimalHeaderLength()
+{
+ size_t minimumHeaderLength;
+ minimumHeaderLength = sizeof(CCNxCodecSchemaV1FixedHeader);
+ return minimumHeaderLength;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h
new file mode 100755
index 00000000..c2690b9f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h
@@ -0,0 +1,135 @@
+/*
+ * 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 rta_TlvPacket.h
+ * @brief Encode and decode a packet using the TLV 1.1 codec
+ *
+ * Will choose the appropriate schema based on the packet version
+ *
+ */
+
+#ifndef TransportRTA_rta_TlvPacketDecoder_h
+#define TransportRTA_rta_TlvPacketDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Decodes a packet in to a dictionary
+ *
+ * The buffer must point to byte 0 of the FixedHeader. It may extend beyond the
+ * end of the packet.
+ *
+ * @param [in] packetBuffer The wire format representation of a packet
+ *
+ * @retval non-null An allocated dictionary
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecTlvPacket_Decode(PARCBuffer *packetBuffer);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvPacket_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvPacket_IoVecDecode(CCNxCodecNetworkBufferIoVec *vec, CCNxTlvDictionary *packetDictionary);
+
+
+/**
+ * Encode the packetDictionary to wire format
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is based
+ * on the dictionary schema version, and the length fields of the fixed header are calculated.
+ * If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * The signer is not stored beyond the call to DictionaryEncode.
+ * If the dictionary already has a ValidationAlg and ValidationPayload, those are used, not the Signer.
+ * Otherwise, if the signer is not null, it is used to sign the wire format.
+ *
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ * @param [in] signer If not NULL will be used to sign the wire format
+ *
+ * @retval non-null An IoVec that can be written to the network
+ * @retval null an error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecTlvPacket_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer);
+
+/**
+ * Return the length of the wire format packet based on information in the header
+ *
+ * @param [in] packetBuffer a PARCBuffer containing, at least, the wire format header
+ * @return length of the message in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvPacket_GetPacketLength(PARCBuffer *packetBuffer);
+
+/**
+ * Return the minimal header that must be read to determine type and packet size
+ *
+ * @return length of the header which must be read in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvPacket_MinimalHeaderLength();
+
+#endif // TransportRTA_rta_TlvPacketDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c
new file mode 100644
index 00000000..4b90abf1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <LongBow/runtime.h>
+
+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);
+}
+
+bool
+ccnxCodecTlvUtilities_DecodeSubcontainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t key, uint16_t length,
+ bool (*subcontainerDecoder)(CCNxCodecTlvDecoder *, CCNxTlvDictionary *))
+{
+ bool success = false;
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, length);
+ if (innerDecoder) {
+ success = subcontainerDecoder(innerDecoder, packetDictionary);
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsInteger(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey)
+{
+ uint64_t value;
+ if (ccnxCodecTlvDecoder_GetVarInt(decoder, length, &value)) {
+ return ccnxTlvDictionary_PutInteger(packetDictionary, dictionaryKey, value);
+ }
+ return false;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ bool success = false;
+ CCNxName *name = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ success = ccnxTlvDictionary_PutName(packetDictionary, arrayKey, name);
+ ccnxName_Release(&name);
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, arrayKey, buffer);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsHash(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, length);
+ bool success = false;
+ if (hash != NULL) {
+ success = ccnxTlvDictionary_PutObject(packetDictionary, arrayKey, (const PARCObject *) hash);
+ parcCryptoHash_Release(&hash);
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsListBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int listKey)
+{
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ bool success = ccnxTlvDictionary_PutListBuffer(packetDictionary, listKey, type, buffer);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+ssize_t
+ccnxCodecTlvUtilities_NestedEncode(CCNxCodecTlvEncoder *outerEncoder, CCNxTlvDictionary *packetDictionary, uint32_t nestedType,
+ ssize_t (*nestedEncoderFunction)(CCNxCodecTlvEncoder *protoInfoEncoder, CCNxTlvDictionary *packetDictionary))
+{
+ size_t startPosition = ccnxCodecTlvEncoder_Position(outerEncoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(outerEncoder, nestedType, 0);
+ ssize_t nestedLength = nestedEncoderFunction(outerEncoder, packetDictionary);
+ if (nestedLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(outerEncoder, startPosition, nestedLength);
+ } else {
+ // rewind the container
+ ccnxCodecTlvEncoder_SetPosition(outerEncoder, startPosition);
+ return nestedLength;
+ }
+
+ size_t endPosition = ccnxCodecTlvEncoder_Position(outerEncoder);
+ return endPosition - startPosition;
+}
+
+ssize_t
+ccnxCodecTlvUtilities_EncodeCustomList(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary, int listKey)
+{
+ ssize_t length = 0;
+
+ size_t size = ccnxTlvDictionary_ListSize(packetDictionary, listKey);
+ for (int i = 0; i < size; i++) {
+ PARCBuffer *buffer;
+ uint32_t key;
+
+ ssize_t innerLength = -1;
+ bool success = ccnxTlvDictionary_ListGetByPosition(packetDictionary, listKey, i, &buffer, &key);
+ if (success) {
+ innerLength = ccnxCodecTlvEncoder_AppendBuffer(encoder, key, buffer);
+ }
+
+ if (innerLength < 0) {
+ return -1;
+ }
+
+ length += innerLength;
+ }
+
+ return length;
+}
+
+bool
+ccnxCodecTlvUtilities_GetVarInt(PARCBuffer *input, size_t length, uint64_t *output)
+{
+ assertNotNull(input, "Parameter input must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ bool success = false;
+ if (length >= 1 && length <= 8 && parcBuffer_Remaining(input) >= length) {
+ uint64_t value = 0;
+ for (int i = 0; i < length; i++) {
+ value = value << 8 | parcBuffer_GetUint8(input);
+ }
+ *output = value;
+ success = true;
+ }
+ return success;
+}
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
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c
new file mode 100755
index 00000000..588694b0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c
@@ -0,0 +1,137 @@
+/*
+ * 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 <config.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+
+bool
+ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue)
+{
+ bool matchFound = false;
+ switch (parcSuite) {
+ case PARCCryptoSuite_RSA_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ matchFound = true;
+ break;
+
+ case PARCCryptoSuite_DSA_SHA256:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_RSA_SHA512:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_HMAC_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ matchFound = true;
+ break;
+
+ case PARCCryptoSuite_HMAC_SHA512:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ matchFound = true;
+ break;
+
+ default:
+ // unknown
+ break;
+ }
+ return matchFound;
+}
+
+bool
+ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite)
+{
+ bool matchFound = false;
+ switch (tlvValue) {
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256:
+ *outputSuite = PARCCryptoSuite_RSA_SHA256;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C:
+ *outputSuite = PARCCryptoSuite_NULL_CRC32C;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256:
+ *outputSuite = PARCCryptoSuite_HMAC_SHA256;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1:
+ // not supported yet
+ break;
+
+ default:
+ // unknown
+ break;
+ }
+ return matchFound;
+}
+
+bool
+ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue)
+{
+ bool matchFound = false;
+ switch (signAlgorithm) {
+ case PARCSigningAlgorithm_RSA: {
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ matchFound = true;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case PARCSigningAlgorithm_HMAC: {
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ matchFound = true;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case PARCSigningAlgortihm_NULL: {
+ switch (hashType) {
+ case PARCCryptoHashType_CRC32C:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ matchFound = true;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return matchFound;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h
new file mode 100755
index 00000000..68e90749
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h
@@ -0,0 +1,85 @@
+/*
+ * 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 ccnxCodecSchemaV1_CryptoSuite.h
+ * @brief Translates between PARC CryptoSuite values and the wire encoding
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#include <stdbool.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+/**
+ * Converts a PARC Crypto Suite to its TLV value
+ *
+ * Looks up the PARC cryptosuite value and returns the corresponding TLV wire format value.
+ * If no match is found, returns false and outputSuite is not modified.
+ *
+ *
+ * @param [in] parcSuite The PARC cryptosuite
+ * @param [out] outputValue The wire encoding equivalent
+ *
+ * @retval true if supported suite and outputValue set.
+ * @retval false if not supported.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue);
+
+/**
+ * Converts a wire format cryptosuite value to the PARC cryptosuite
+ *
+ * Looks up the TLV wire format value and returns the corresponding PARC cryptosuite.
+ * If no match is found, returns false and outputSuite is not modified.
+ *
+ * @param [in] tlvValue The wire format value
+ * @param [out] outputValue The PARC equivalent
+ *
+ * @return true if match found and parcSuite set.
+ * @return false if no match found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite);
+
+/**
+ * Lookup a signing algorithm and hash type and convert to a wire format value
+ *
+ * Based on a PARCSigner's algorithm and hash type, find the corresponding wire format crypto suite.
+ *
+ * @param [in] signAlgorithm The signing algorithm
+ * @param [in] hashType The hash used by the signing algorithm
+ * @param [out] outputValue The wire format value
+ *
+ * @retval true if supported suite and outputValue set.
+ * @retval false if not supported.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue);
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h
new file mode 100755
index 00000000..3055c054
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h
@@ -0,0 +1,51 @@
+/*
+ * 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 ccnxCodecSchemaV1_FixedHeader.h
+ * @brief common definitions and functions for the FixedHeader
+ *
+ * See ccnxCodecSchemaV1_Packet.h for an overview of the version 1 codec
+ *
+ * This is the one file you need to include for all FixedHeader operations. It will
+ * include all the Decoders and Encoders.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
+#define TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
+
+typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_fixed_header {
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t reserved[3];
+ uint8_t headerLength;
+} CCNxCodecSchemaV1FixedHeader;
+
+typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_interest_header {
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t hopLimit;
+ uint8_t returnCode;
+ uint8_t flags;
+ uint8_t headerLength;
+} CCNxCodecSchemaV1InterestHeader;
+
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h>
+#endif // TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c
new file mode 100755
index 00000000..fcec49b3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c
@@ -0,0 +1,210 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static const size_t _fixedHeaderBytes = 8;
+
+static const int _fixedHeader_VersionOffset = 0;
+static const int _fixedHeader_PacketTypeOffset = 1;
+static const int _fixedHeader_PacketLengthOffset = 2;
+static const int _fixedHeader_HopLimitOffset = 4;
+static const int _fixedHeader_ReturnCodeOffset = 5;
+static const int _fixedHeader_FlagsOffset = 6;
+static const int _fixedHeader_HeaderLengthOffset = 7;
+
+bool
+ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, _fixedHeaderBytes)) {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, _fixedHeaderBytes);
+ bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader, buffer);
+
+ // validation
+ parcBuffer_SetPosition(buffer, _fixedHeader_VersionOffset);
+ uint8_t version = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_PacketLengthOffset);
+ uint16_t packetLength = parcBuffer_GetUint16(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_ReturnCodeOffset);
+ uint8_t interestReturnCode = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_HopLimitOffset);
+ uint8_t hopLimit = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_HeaderLengthOffset);
+ uint8_t headerLength = parcBuffer_GetUint8(buffer);
+
+ if (version != 1) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_VERSION, __func__, __LINE__, _fixedHeader_VersionOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (packetLength < _fixedHeaderBytes) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (headerLength < _fixedHeaderBytes) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_HEADERLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_HeaderLengthOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (packetLength < headerLength) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTHSHORTER, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ }
+
+ // decoder now points to just past the fixed header
+ parcBuffer_Release(&buffer);
+
+ // Set the hoplimit in the dictionary.
+ ccnxTlvDictionary_PutInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit);
+
+ // Set the InterestReturn code in the dictionary.
+ ccnxTlvDictionary_PutInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode,
+ interestReturnCode);
+
+ return success;
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ return false;
+ }
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_VersionOffset);
+ uint8_t version = parcBuffer_GetUint8(fixedHeader);
+ return version;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketTypeOffset);
+ uint8_t packetType = parcBuffer_GetUint8(fixedHeader);
+ return packetType;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketLengthOffset);
+ uint16_t payloadLength = parcBuffer_GetUint16(fixedHeader);
+ return payloadLength;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary)
+{
+ int length = -1;
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_HeaderLengthOffset);
+ uint8_t headerLength = parcBuffer_GetUint8(fixedHeader);
+
+ // 8 is the minimum size of headerLength
+ if (headerLength >= _fixedHeaderBytes) {
+ length = headerLength;
+ }
+ }
+
+ return length;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary)
+{
+ int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(packetDictionary);
+ return headerLength - _fixedHeaderBytes;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_HopLimitOffset);
+ uint8_t hopLimit = parcBuffer_GetUint8(fixedHeader);
+ return hopLimit;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_ReturnCodeOffset);
+ uint8_t returnCode = parcBuffer_GetUint8(fixedHeader);
+ return returnCode;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_FlagsOffset);
+ uint8_t flags = parcBuffer_GetUint8(fixedHeader);
+ return flags;
+ }
+
+ return -1;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h
new file mode 100755
index 00000000..5d15f40b
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+/**
+ */
+#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
+#define Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a V1 fixed header
+ *
+ * The decoder should point to byte 0 of the Fixed Header.
+ * It will be advanced to the first byte following it.
+ * The results are put in the provided.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] dictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the version
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The Version
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the PacketType
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The PacketType
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the PacketLength
+ *
+ * The PacketLength is measured from byte 0 to the end of the packet
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The packet length (in host byte order)
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the HeaderLength
+ *
+ * In a version 1 packet, the header length includes the fixed header. It is measured from
+ * byte 0 to the end of the hop-by-hop headers.
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The header length
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Returns the bytes of the optional headers
+ *
+ * Computes ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength() - sizeof(fixedHeader)
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @retval non-negative The length of the optional headers
+ * @retval negative An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary);
+
+
+/**
+ * A convenience function to return the ReturnCode of an Interest or InterestReturn
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The Return Code
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the header Flags
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The flags
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary);
+
+#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c
new file mode 100755
index 00000000..3b6eca67
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c
@@ -0,0 +1,64 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+ssize_t
+ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder, const CCNxCodecSchemaV1FixedHeader *header)
+{
+ assertNotNull(fixedHeaderEncoder, "Parameter fixedHeaderEncoder must be non-null");
+ assertNotNull(header, "Parameter header must be non-null");
+ trapIllegalValueIf(header->version != 1, "Header wrong version, must be 1");
+
+ CCNxCodecSchemaV1InterestHeader copy;
+
+ memcpy(&copy, header, sizeof(CCNxCodecSchemaV1InterestHeader));
+
+ copy.packetLength = htons(header->packetLength);
+
+ switch (header->packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ copy.returnCode = 0;
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ // nothing to do, all fields used
+ break;
+
+ default:
+ copy.hopLimit = 0;
+ copy.returnCode = 0;
+ copy.flags = 0;
+ break;
+ }
+
+ ccnxCodecTlvEncoder_AppendRawArray(fixedHeaderEncoder, sizeof(CCNxCodecSchemaV1FixedHeader), (uint8_t *) &copy);
+ return sizeof(CCNxCodecSchemaV1FixedHeader);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h
new file mode 100755
index 00000000..0981f4bd
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h
@@ -0,0 +1,50 @@
+/*
+ * 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 ccnxCodecSchemaV1_FixedHeaderEncoder.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
+#define Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+/**
+ * Set the values in the fixed header
+ *
+ * Put the provided fixed header at the given byte location. The provided fixed header is not put
+ * in as-is (i.e byte for byte), but is parsed and put in the correct byte positions and encodings
+ * assuming the fixed header starts at the given position.
+ *
+ * The encoder is returned to its current position after putting the header.
+ *
+ * @param [in] encoder The encoder to append the fixed header in to
+ * @param [in] The header, in host byte order
+ *
+ * @return Number The bytes appended, or -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *encoder, const CCNxCodecSchemaV1FixedHeader *header);
+#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c
new file mode 100644
index 00000000..23a559cc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c
@@ -0,0 +1,149 @@
+/*
+ * 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 <config.h>
+
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+
+/**
+ * These are the accepted sizes for the pre-defined hash types.
+ * Hash TLVs with lengths that do not match one of these values will be deemed
+ * invalid and not parse correctly.
+ */
+static const size_t _PARCCryptoHashType_SHA256_Sizes[] = { 32 };
+static const size_t _PARCCryptoHashType_SHA512_Sizes[] = { 32, 64 };
+
+static bool
+_ccnxCodecSchemaV1HashCodec_ValidHashSize(size_t size, size_t numSizes, size_t sizes[numSizes])
+{
+ for (size_t i = 0; i < numSizes; i++) {
+ if (sizes[i] == size) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ssize_t
+ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash)
+{
+ PARCBuffer *digest = parcCryptoHash_GetDigest(hash);
+ PARCCryptoHashType hashType = parcCryptoHash_GetDigestType(hash);
+ size_t digestLength = parcBuffer_Remaining(digest);
+
+ uint16_t tlvHashType = CCNxCodecSchemaV1Types_HashType_App;
+ bool validHash = true;
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA256;
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength,
+ sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes);
+ break;
+ case PARCCryptoHashType_SHA512:
+ tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA512;
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength,
+ sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes);
+ break;
+ default:
+ break;
+ }
+
+ if (validHash) {
+ return ccnxCodecTlvEncoder_AppendBuffer(encoder, tlvHashType, digest);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ return -1;
+ }
+}
+
+static bool
+_ccnxCodecSchemaV1HashCodec_ValidHash(uint16_t hashType, uint16_t hashSize)
+{
+ bool validHash = true;
+
+ switch (hashType) {
+ case CCNxCodecSchemaV1Types_HashType_SHA256:
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize,
+ sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_SHA512:
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize,
+ sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes);
+ break;
+ default:
+ break;
+ }
+
+ return validHash;
+}
+
+PARCCryptoHash *
+ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t limit)
+{
+ PARCCryptoHash *hash = NULL;
+ uint16_t hashType = 0;
+ uint16_t length = 0;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ hashType = ccnxCodecTlvDecoder_GetType(decoder);
+ length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (length > limit) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ return NULL;
+ }
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ switch (hashType) {
+ case CCNxCodecSchemaV1Types_HashType_SHA256:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, value);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_SHA512:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_SHA512, value);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_App:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_NULL, value);
+ break;
+ }
+ parcBuffer_Release(&value);
+ }
+ }
+
+ // Verify the hash size, if one was parsed correctly.
+ if (hash != NULL && !_ccnxCodecSchemaV1HashCodec_ValidHash(hashType, length)) {
+ parcCryptoHash_Release(&hash);
+ }
+
+ return hash;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h
new file mode 100755
index 00000000..f03b3746
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h
@@ -0,0 +1,74 @@
+/*
+ * 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 ccnxCodecSchemaV1_HashCodec.h
+ * @brief A cryptographic hash digest encoded
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
+#define __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+#include <parc/security/parc_CryptoHash.h>
+
+/**
+ * Encodes the hash, but without a "TL" container
+ *
+ * Will append the Link in it's well-known TLV format, but without any
+ * "TL" container.
+ *
+ * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY.
+ *
+ * @param [in] encoder The hash will be appended to the encoder
+ * @param [in] hash The hash to append
+ *
+ * @retval non-negative The number of bytes appended to the encoder
+ * @retval negative An error, look at the CCNxCodecError of the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash);
+
+/**
+ * The decoder points to the first byte of the "value" of something that is a Link
+ *
+ * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject
+ * of type Link, it should be the first byte of the Payload.
+ *
+ * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and
+ * Hash is the ContentObjectHash restriction to use in an Interest for Name.
+ * No additional fields are allowed in the Link.
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Hash value
+ *
+ * @return non-null A parsed name
+ * @return null An error, check the decoder's error message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHash *ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t length);
+
+#endif // __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c
new file mode 100755
index 00000000..cc78c28e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c
@@ -0,0 +1,165 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+
+ssize_t
+ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link)
+{
+ ssize_t length = 0;
+
+ const CCNxName *name = ccnxLink_GetName(link);
+ if (name) {
+ length += ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_Link_Name, name);
+
+ PARCBuffer *keyid = ccnxLink_GetKeyID(link);
+ if (keyid) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_KeyIdRestriction, keyid);
+ }
+
+ PARCBuffer *hash = ccnxLink_GetContentObjectHash(link);
+ if (hash) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction, hash);
+ }
+ } else {
+ length = -1;
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return length;
+}
+
+typedef struct decoded_link {
+ CCNxName *linkName;
+ PARCBuffer *linkKeyId;
+ PARCBuffer *linkHash;
+} _DecodedLink;
+
+static int
+_decodeField(CCNxCodecTlvDecoder *decoder, _DecodedLink *decodedLink)
+{
+ int errorCode = TLV_ERR_NO_ERROR;
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ switch (type) {
+ case CCNxCodecSchemaV1Types_Link_Name:
+ if (decodedLink->linkName == NULL) {
+ decodedLink->linkName = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ case CCNxCodecSchemaV1Types_Link_KeyIdRestriction:
+ if (decodedLink->linkKeyId == NULL) {
+ decodedLink->linkKeyId = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ case CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction:
+ if (decodedLink->linkHash == NULL) {
+ decodedLink->linkHash = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ default:
+ // we do not support unknown TLVs
+ errorCode = TLV_ERR_DECODE;
+ break;
+ }
+ } else {
+ errorCode = TLV_ERR_TOO_LONG;
+ }
+
+ return errorCode;
+}
+
+static void
+_decodecLinkCleanup(_DecodedLink *decodedLink)
+{
+ if (decodedLink->linkName) {
+ ccnxName_Release(&decodedLink->linkName);
+ }
+
+ if (decodedLink->linkKeyId) {
+ parcBuffer_Release(&decodedLink->linkKeyId);
+ }
+
+ if (decodedLink->linkHash) {
+ parcBuffer_Release(&decodedLink->linkHash);
+ }
+}
+
+CCNxLink *
+ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t linkLength)
+{
+ int errorCode = TLV_ERR_NO_ERROR;
+
+ CCNxLink *link = NULL;
+
+ _DecodedLink decodedLink;
+ memset(&decodedLink, 0, sizeof(_DecodedLink));
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, linkLength)) {
+ while (errorCode == TLV_ERR_NO_ERROR && ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ errorCode = _decodeField(decoder, &decodedLink);
+ }
+ } else {
+ errorCode = TLV_ERR_TOO_LONG;
+ }
+
+ if (errorCode == TLV_ERR_NO_ERROR && decodedLink.linkName == NULL) {
+ errorCode = TLV_ERR_DECODE;
+ }
+
+ if (errorCode != TLV_ERR_NO_ERROR) {
+ CCNxCodecError *error = ccnxCodecError_Create(errorCode, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ } else {
+ link = ccnxLink_Create(decodedLink.linkName, decodedLink.linkKeyId, decodedLink.linkHash);
+ }
+
+ // cleanup any partial memory allocations
+ _decodecLinkCleanup(&decodedLink);
+
+ return link;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h
new file mode 100755
index 00000000..4163aa1d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h
@@ -0,0 +1,76 @@
+/*
+ * 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 ccnxCodecSchemaV1_LinkCodec.h
+ * @brief A Link is a well-known value, not a TLV field
+ *
+ * A Link may be the "value" of a TLV element, such as the KeyName. It can also occur
+ * in the payload of a ContentObject whose PayloadType is Link.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__
+#define __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__
+
+#include <ccnx/common/ccnx_Link.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * Encodes the link, but without a "TL" container
+ *
+ * Will append the Link in it's well-known TLV format, but without any
+ * "TL" container.
+ *
+ * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY.
+ *
+ * @param [in] encoder The link will be appended to the encoder
+ * @param [in] link The link to append
+ *
+ * @retval non-negative The number of bytes appended to the encoder
+ * @retval negative An error, look at the CCNxCodecError of the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link);
+
+/**
+ * The decoder points to the first byte of the "value" of something that is a Link
+ *
+ * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject
+ * of type Link, it should be the first byte of the Payload.
+ *
+ * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and
+ * Hash is the ContentObjectHash restriction to use in an Interest for Name.
+ * No additional fields are allowed in the Link.
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Link value
+ *
+ * @return non-null A parsed name
+ * @return null An error, check the decoder's error message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxLink *ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_LinkCodec__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c
new file mode 100644
index 00000000..87665de1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c
@@ -0,0 +1,187 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+static bool
+_decodeHashGroupMetadata(CCNxCodecTlvDecoder *decoder, CCNxManifestHashGroup *group, size_t length)
+{
+ size_t offset = 0;
+ bool success = true;
+
+ while (offset < length) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder);
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+
+ offset += (4 + value_length);
+
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator: {
+ char *nameString = parcBuffer_ToString(value);
+ const CCNxName *locator = ccnxName_CreateFromCString(nameString);
+ ccnxManifestHashGroup_SetLocator(group, locator);
+ parcMemory_Deallocate(&nameString);
+ ccnxName_Release((CCNxName **) &locator);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize: {
+ uint64_t dataSize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize: {
+ uint64_t blockSize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize: {
+ uint64_t entrySize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight: {
+ uint64_t treeHeight = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256: {
+ ccnxManifestHashGroup_SetOverallDataDigest(group, value);
+ break;
+ }
+ }
+
+ parcBuffer_Release(&value);
+ }
+
+ return success;
+}
+
+static bool
+_decodeHashGroup(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, CCNxManifestHashGroup *group, size_t length)
+{
+ bool success = true;
+ size_t offset = 0;
+
+ while (offset < length) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ offset += (4 + value_length);
+
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata: {
+ success = _decodeHashGroupMetadata(decoder, group, value_length);
+ if (!success) {
+ return false;
+ }
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer: {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer);
+ parcBuffer_Release(&buffer);
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer: {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer);
+ parcBuffer_Release(&buffer);
+ break;
+ }
+
+ default:
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, value_length, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ }
+
+ CCNxManifestInterface *manifest = ccnxManifestInterface_GetInterface(packetDictionary);
+ manifest->addHashGroup(packetDictionary, group);
+
+ return success;
+}
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxMessage_Name: {
+ success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_HashGroup: {
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ success = _decodeHashGroup(decoder, packetDictionary, group, length);
+ ccnxManifestHashGroup_Release(&group);
+ 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, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, manifestDictionary, _decodeType);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h
new file mode 100755
index 00000000..1726e41e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h
@@ -0,0 +1,52 @@
+/*
+ * 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 ccnxCodecSchemaV1_ManifestDecoder.h
+ * @brief Decode the body of a CCNx Manifest.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * Decode a V1 Manifest.
+ *
+ * The decoder should point to byte 0 of a Manifest (message) TLV.
+ * The results are put in the provided dictionary.
+ * It is an error if the message does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] manifestDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c
new file mode 100644
index 00000000..0d8f52bf
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c
@@ -0,0 +1,166 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+static size_t
+_appendPointer(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroupPointer *ptr)
+{
+ const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr);
+ CCNxManifestHashGroupPointerType type = ccnxManifestHashGroupPointer_GetType(ptr);
+
+ ssize_t length = -1;
+ switch (type) {
+ case CCNxManifestHashGroupPointerType_Data:
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer, (PARCBuffer *) digest);
+ break;
+ case CCNxManifestHashGroupPointerType_Manifest:
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer, (PARCBuffer *) digest);
+ break;
+ default:
+ assertTrue(false, "Invalid pointer type %d", type);
+ }
+
+ if (length < 0) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return length;
+}
+
+ssize_t
+_appendMetadata(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroup *group)
+{
+ ssize_t length = 0;
+
+ // Pre-populate this field -- we'll come back and fill in the length after we're done
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, length);
+
+ // Now append all metadata that exists in the hash group.
+ const CCNxName *locator = ccnxManifestHashGroup_GetLocator(group);
+ if (locator != NULL) {
+ char *nameString = ccnxName_ToString(locator);
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(nameString);
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, nameBuffer);
+ parcBuffer_Release(&nameBuffer);
+ parcMemory_Deallocate(&nameString);
+ }
+
+ size_t dataSize = ccnxManifestHashGroup_GetDataSize(group);
+ if (dataSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, dataSize);
+ }
+
+ size_t blockSize = ccnxManifestHashGroup_GetBlockSize(group);
+ if (blockSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, blockSize);
+ }
+
+ size_t entrySize = ccnxManifestHashGroup_GetEntrySize(group);
+ if (entrySize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, entrySize);
+ }
+
+ size_t treeSize = ccnxManifestHashGroup_GetTreeHeight(group);
+ if (treeSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, treeSize);
+ }
+
+ const PARCBuffer *dataDigest = ccnxManifestHashGroup_GetOverallDataDigest(group);
+ if (dataDigest != NULL) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, (PARCBuffer *) dataDigest);
+ }
+
+ // Rewind back to the container opening and fill in the length
+ size_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_PutUint16(encoder, startPosition, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata);
+ ccnxCodecTlvEncoder_PutUint16(encoder, startPosition + 2, length);
+ ccnxCodecTlvEncoder_SetPosition(encoder, endPosition);
+
+ return endPosition - startPosition;
+}
+
+ssize_t
+ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ ssize_t numHashGroups = ccnxTlvDictionary_ListSize(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST);
+ for (size_t i = 0; i < numHashGroups; i++) {
+ // Skip past the TL of the hash group to append the pointers inside
+ ssize_t groupLength = 0;
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup, groupLength);
+
+ CCNxManifestInterface *interface = ccnxManifestInterface_GetInterface(packetDictionary);
+ CCNxManifestHashGroup *group = interface->getHashGroup(packetDictionary, i);
+
+ // Encode any metadata, if present.
+ if (ccnxManifestHashGroup_HasMetadata(group)) {
+ groupLength += _appendMetadata(encoder, group);
+ }
+
+ // Append the HashGroup pointers
+ size_t numPointers = ccnxManifestHashGroup_GetNumberOfPointers(group);
+ for (size_t p = 0; p < numPointers; p++) {
+ CCNxManifestHashGroupPointer *ptr = ccnxManifestHashGroup_GetPointerAtIndex(group, p);
+ ssize_t ptrLength = _appendPointer(encoder, ptr);
+ if (ptrLength < 0) {
+ return ptrLength;
+ }
+ groupLength += ptrLength;
+ }
+
+ // Now that we know the overall length, rewind back to the start and append the TL
+ // part of the container.
+ size_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ssize_t offset = endPosition - groupLength - 4;
+ ccnxCodecTlvEncoder_PutUint16(encoder, offset, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup);
+ ccnxCodecTlvEncoder_PutUint16(encoder, offset + 2, groupLength);
+ ccnxCodecTlvEncoder_SetPosition(encoder, endPosition);
+
+ length += groupLength + 4;
+
+ ccnxManifestHashGroup_Release(&group);
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h
new file mode 100755
index 00000000..4951cf80
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h
@@ -0,0 +1,31 @@
+/*
+ * 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 ccnxCodecSchemaV1_ManifestEncoder.h
+ * @brief Encode a V1 Manifest.
+ *
+ */
+
+#ifndef ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
+#define ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+ssize_t ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c
new file mode 100644
index 00000000..f0dea7a6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c
@@ -0,0 +1,140 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+static bool
+_translateWirePayloadTypeToCCNxPayloadType(CCNxCodecSchemaV1Types_PayloadType wireFormatType, CCNxPayloadType *payloadTypePtr)
+{
+ bool success = true;
+ switch (wireFormatType) {
+ case CCNxCodecSchemaV1Types_PayloadType_Data:
+ *payloadTypePtr = CCNxPayloadType_DATA;
+ break;
+
+ case CCNxCodecSchemaV1Types_PayloadType_Key:
+ *payloadTypePtr = CCNxPayloadType_KEY;
+ break;
+
+ case CCNxCodecSchemaV1Types_PayloadType_Link:
+ *payloadTypePtr = CCNxPayloadType_LINK;
+ break;
+
+ default:
+ // unknown type
+ success = false;
+ }
+ return success;
+}
+
+/**
+ * Translates the wire format value for the PayloadType to CCNxPayloadType
+ */
+static bool
+_decodePayloadType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t length)
+{
+ CCNxPayloadType payloadType;
+
+ uint64_t wireFormatVarInt;
+ bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, length, &wireFormatVarInt);
+ if (success) {
+ CCNxCodecSchemaV1Types_PayloadType wireFormatType = (CCNxCodecSchemaV1Types_PayloadType) wireFormatVarInt;
+
+ success = _translateWirePayloadTypeToCCNxPayloadType(wireFormatType, &payloadType);
+ }
+
+ if (success) {
+ success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType);
+ }
+
+ return success;
+}
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxMessage_Name:
+ success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_Payload:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction:
+ success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction:
+ success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_PayloadType:
+ success = _decodePayloadType(decoder, packetDictionary, length);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ 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, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h
new file mode 100755
index 00000000..30a998aa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h
@@ -0,0 +1,57 @@
+/*
+ * 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 ccnxCodecSchemaV1_MessageDecoder.h
+ * @brief <#Brief Description#>
+ *
+ * Decodes the CCNx message body for an Interest or a ContentObject.
+ *
+ * The current CPI Control packet does not use the MessageDecoder or MessageEncoder. It is handled
+ * entirely in the Packet{De,En}coder.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a V1 message, maybe any message type
+ *
+ * The decoder should point to byte 0 of the message TLV
+ * The results are put in the provided dictionary.
+ * It is an error if the message does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] contentObjectDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *contentObjectDictionary);
+
+
+#endif // TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c
new file mode 100755
index 00000000..7aa14627
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c
@@ -0,0 +1,340 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+static ssize_t
+_encodeName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = -1;
+ CCNxName *name = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ if (name != NULL) {
+ length = ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Name, name);
+ }
+
+ // required field for everything except CCNxContentObjects
+ if (!ccnxTlvDictionary_IsContentObject(packetDictionary) && length < 0) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) && name == NULL) {
+ length = 0;
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeJsonPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (json != NULL) {
+ char *jsonString = parcJSON_ToCompactString(json);
+ size_t len = strlen(jsonString);
+ length = ccnxCodecTlvEncoder_AppendArray(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, len, (uint8_t *) jsonString);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePayloadType(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) {
+ CCNxPayloadType payloadType = (CCNxPayloadType) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+
+ CCNxCodecSchemaV1Types_PayloadType wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Data;
+
+ switch (payloadType) {
+ case CCNxPayloadType_KEY:
+ wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Key;
+ break;
+
+ case CCNxPayloadType_LINK:
+ wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Link;
+ break;
+
+ default:
+ // anything else is encoded as DATA
+ break;
+ }
+
+ length = ccnxCodecTlvEncoder_AppendUint8(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, wireFormatType);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, buffer);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeExpiryTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ uint64_t millis = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, millis);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, buffer);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeEndChunkNumber(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT)) {
+ uint64_t endChunkId = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ length = ccnxCodecTlvEncoder_AppendVarInt(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, endChunkId);
+ } else {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, buffer);
+ }
+ }
+ return length;
+}
+
+static ssize_t
+_encodeKeyIdRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+ if (hash != NULL) {
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction, 0);
+ length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash);
+ if (length < 0) {
+ return length;
+ }
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length);
+ length += 4; // this accounts for the TL fields
+ }
+ return length;
+}
+
+static ssize_t
+_encodeContentObjectHashRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ if (hash != NULL) {
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction, 0);
+ length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash);
+ if (length < 0) {
+ return length;
+ }
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length);
+ length += 4; // this accounts for the TL fields
+ }
+ return length;
+}
+
+
+static ssize_t
+_encodeContentObject(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayloadType(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeExpiryTime(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeEndChunkNumber(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeInterest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeKeyIdRestriction(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeContentObjectHashRestriction(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeControl(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeJsonPayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeManifest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null");
+
+ ssize_t length = -1;
+
+ if (ccnxTlvDictionary_IsInterest(packetDictionary)) {
+ length = _encodeInterest(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ length = _encodeInterest(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ length = _encodeContentObject(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ length = _encodeControl(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ length = _encodeManifest(encoder, packetDictionary);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ length = -1;
+ }
+
+
+ if (length >= 0) {
+ // Put custom fields all last
+ ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(encoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ if (customLength < 0) {
+ return customLength;
+ }
+ length += customLength;
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h
new file mode 100755
index 00000000..d49417fb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h
@@ -0,0 +1,47 @@
+/*
+ * 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 ccnxCodecSchemaV1_MessageEncoder.h
+ * @brief Encode the list of optional headers
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
+#define TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <parc/security/parc_Signer.h>
+
+/**
+ * Encodes the body of the CCNxMessage
+ *
+ * Encodes an Interest, ContentObject, or Control message
+ *
+ * @param [in] encoder Appends the CCNx message to the encoder
+ * @param [in] packetDictionary The fields to encode
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c
new file mode 100755
index 00000000..a769477f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c
@@ -0,0 +1,85 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h>
+
+size_t
+ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertNotNull(name, "Parameter name must be non-null");
+
+ size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder);
+ size_t containerLength = ccnxCodecTlvEncoder_AppendContainer(encoder, type, 0);
+
+ size_t segmentCount = ccnxName_GetSegmentCount(name);
+ size_t innerLength = 0;
+ for (int i = 0; i < segmentCount; i++) {
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, i);
+ innerLength += ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment);
+ }
+
+ // now go back and fixup the container's length
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, innerLength);
+
+ return containerLength + innerLength;
+}
+
+CCNxName *
+ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type)
+{
+ CCNxName *name = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ uint16_t tlvtype = ccnxCodecTlvDecoder_PeekType(decoder);
+ if (tlvtype == type) {
+ // call just for the side-effect of advancing the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ name = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ }
+ }
+
+ return name;
+}
+
+CCNxName *
+ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ CCNxName *name = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ name = ccnxName_Create();
+ size_t nameEnd = ccnxCodecTlvDecoder_Position(decoder) + length;
+
+ while (ccnxCodecTlvDecoder_Position(decoder) < nameEnd) {
+ CCNxNameSegment *segment = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+ ccnxName_Append(name, segment);
+ ccnxNameSegment_Release(&segment);
+ }
+ }
+ return name;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h
new file mode 100755
index 00000000..6c3298a2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h
@@ -0,0 +1,83 @@
+/*
+ * 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 ccnxCodecSchemaV1_NameCodec.h
+ * @brief TLV codec for CCNx types
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_NameCodec_h
+#define CCNxCodecSchemaV1_NameCodec_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+#include <ccnx/common/ccnx_Name.h>
+
+/**
+ * Encodes the name to the TLV Encoder
+ *
+ * Will append the Name after the current encoder location
+ *
+ * @param [in] type The TLV type to use for the Name container
+ *
+ * @return bytes The number of bytes appended to the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name);
+
+/**
+ * Decode the buffer as a CCNxName beginning at the current position
+ *
+ * The buffer must be pointing to the beginnig of the "type". The decoder will
+ * verify that the type matches `type'. If it does not match, it will return NULL.
+ *
+ * @param [in] decoder The decoder
+ * @param [in] type The TLV type that the decoder should currently be pointing at
+ *
+ * @return non-null The CCNxName decoded
+ * @return null An error: either type did not match or some other error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type);
+
+/**
+ * The decoder points to the first byte of the Name "value"
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Name value
+ *
+ * @return non-null A parsed name
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+#endif // CCNxCodecSchemaV1_NameCodec_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c
new file mode 100755
index 00000000..55d02bab
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c
@@ -0,0 +1,59 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h>
+
+size_t
+ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment)
+{
+ assertTrue(ccnxNameSegment_Length(segment) <= UINT16_MAX,
+ "Name segment too long! length %zu maximum %u",
+ ccnxNameSegment_Length(segment),
+ UINT16_MAX);
+
+ uint16_t segment_type = ccnxNameSegment_GetType(segment);
+ PARCBuffer *value = ccnxNameSegment_GetValue(segment);
+
+ return ccnxCodecTlvEncoder_AppendBuffer(encoder, segment_type, value);
+}
+
+CCNxNameSegment *
+ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder)
+{
+ CCNxNameSegment *segment = NULL;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ segment = ccnxNameSegment_CreateTypeValue(type, value);
+ parcBuffer_Release(&value);
+ }
+ }
+
+ return segment;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h
new file mode 100755
index 00000000..c6797cff
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ccnxCodecSchemaV1_NameSegmentCodec.h
+ * @brief TLV codec for CCNx types
+ *
+ * Encode/decode a CCNx name segment using the V1 schema
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_NameSegmentCodec_h
+#define CCNxCodecSchemaV1_NameSegmentCodec_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+#include <ccnx/common/ccnx_Name.h>
+
+/**
+ * Encodes the name segment using the segment type as the TLV type
+ *
+ * Appends the name segment to the encoder. The TLV type is implicit in
+ * the CCNxNameSegment.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return number The number of bytes appended, including the type and length.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment);
+
+/**
+ * Decodes the current location of the decoder as a CCNxNameSegment
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] decoder The decoder object
+ *
+ * @return non-null A CCNxNameSement
+ * @return null An error, such as buffer underrun
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxNameSegment *ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder);
+#endif // CCNxCodecSchemaV1_NameSegmentCodec_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c
new file mode 100755
index 00000000..48554b9a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime:
+ // its a time, so use an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime:
+ // its a time, so use an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ break;
+ case CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ 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, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ }
+ break;
+ }
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType);
+}
+
+// ==== Getters
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ return buffer;
+}
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ return buffer;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ return lifetime;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t cachetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ return cachetime;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetPathLabel(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ return pathLabel;
+}
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_ListGetByType(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS, key);
+ return buffer;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h
new file mode 100755
index 00000000..94463ad1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h
@@ -0,0 +1,144 @@
+/*
+ * 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 ccnxCodecSchemaV1_OptionalHeadersDecoder.h
+ * @brief Decode the list of optional headers
+ *
+ * A reference to each optional header will be stored in the provided CCNxTlvDictionary.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a list of Version 1 optional headers
+ *
+ * The decoder should point to the first byte of the first optional header.
+ * The decoder will advance until the end of the buffer.
+ * It is an error for the last optional header to either go beyond the end of the
+ * decoder or for it to underrun the end of the decoder. It must exactly align.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Interest Fragment header buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return non-null The header buffer
+ * @return null The header does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Content Object Fragment header buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return non-null The header buffer
+ * @return null The header does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Interest Lifetime header value
+ *
+ * Returns the byte array of the Interest Lifetime, which is encoded as a uint64_t milli-seconds
+ * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the
+ * buffer will be reflected in the header.
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return number The Interest Lifetime
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Recommended Cache Time (RCT) header
+ *
+ * Returns the byte array of the RCT, which is encoded as a uint64_t milli-seconds
+ * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the
+ * buffer will be reflected in the header.
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return number The Recommended Cache Time
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary);
+
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedPathLabel(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Retrieves a TLV header that is not part of the V1 schema spec
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-NULL The header
+ * @return NULL The header field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c
new file mode 100755
index 00000000..f108a1c3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c
@@ -0,0 +1,187 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static ssize_t
+_EncodeInterestLifetime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ // allow either encoding as an Integer or as a Buffer
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) {
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) {
+ PARCBuffer *lifetime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodeRecommendedCacheTime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ // allow either encoding as an Integer or as a Buffer
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) {
+ uint64_t cacheTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) {
+ PARCBuffer *cacheTime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodePathLabel(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ uint16_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ PARCBuffer *pathLabel = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodeInterestFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_EncodeContentObjectFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_EncodeInterestHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t intFragLength = _EncodeInterestFrag(optionalHeadersEncoder, packetDictionary);
+ if (intFragLength < 0) {
+ return intFragLength;
+ }
+ length += intFragLength;
+
+ ssize_t intLifeLength = _EncodeInterestLifetime(optionalHeadersEncoder, packetDictionary);
+ if (intLifeLength < 0) {
+ return intLifeLength;
+ }
+ length += intLifeLength;
+
+ ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ if (customLength < 0) {
+ return customLength;
+ }
+ length += customLength;
+
+ return length;
+}
+
+static ssize_t
+_EncodeContentObjectHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _EncodeContentObjectFrag(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _EncodeRecommendedCacheTime(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _EncodePathLabel(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+
+ssize_t
+ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ assertNotNull(optionalHeadersEncoder, "Parameter optionalHeadersEncoder must be non-null");
+ assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null");
+
+ ssize_t result = 0;
+ if (ccnxTlvDictionary_IsInterest(packetDictionary) || ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ result = _EncodeInterestHeaders(optionalHeadersEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) || ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ result = _EncodeContentObjectHeaders(optionalHeadersEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(optionalHeadersEncoder));
+ ccnxCodecTlvEncoder_SetError(optionalHeadersEncoder, error);
+ ccnxCodecError_Release(&error);
+ result = -1;
+ }
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h
new file mode 100755
index 00000000..3f7632ca
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h
@@ -0,0 +1,46 @@
+/*
+ * 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 ccnxCodecSchemaV1_OptionalHeadersEncoder.h
+ * @brief Encode the list of optional headers
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
+#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+/**
+ * Appends the Optional Headers to the encoderder
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c
new file mode 100644
index 00000000..692b3291
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c
@@ -0,0 +1,289 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/internal/ccnx_WireFormatFacadeV1.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+
+typedef struct rta_tlv_schema_v1_data {
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *packetDictionary;
+} _CCNxCodecSchemaV1Data;
+
+/**
+ * Decodes the per-hop optional headers
+ *
+ * @param [in] data The packet decoder state
+ *
+ * @return true successful decode
+ * @return false A decoding error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_decodeOptionalHeaders(_CCNxCodecSchemaV1Data *data)
+{
+ size_t optionalHeaderLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(data->packetDictionary);
+ CCNxCodecTlvDecoder *optionalHeaderDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, optionalHeaderLength);
+
+ bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(optionalHeaderDecoder, data->packetDictionary);
+
+ ccnxCodecTlvDecoder_Destroy(&optionalHeaderDecoder);
+ return success;
+}
+
+/**
+ * Decodes the "value" of the CPI "TLV"
+ *
+ * the CPI packet is encoded as a single TLV container of type 0xBEEF (detected in _decodeMessage).
+ * At this point, the cpiDecoder wraps the CPI payload, which is the encapsulated JSON
+ *
+ * @param [in] cpiDecoder Decoder wrapping the value
+ * @param [in] packetDictionary where to place the results
+ *
+ * @retval true Good decode
+ * @retval false An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_decodeCPI(CCNxCodecTlvDecoder *cpiDecoder, CCNxTlvDictionary *packetDictionary)
+{
+ // we just take the whole contents of the decoder and put in the the PAYLOAD dictionary entry.
+ size_t length = ccnxCodecTlvDecoder_Remaining(cpiDecoder);
+ PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(cpiDecoder, length);
+
+ PARCJSON *json = parcJSON_ParseBuffer(payload);
+
+ bool success = ccnxTlvDictionary_PutJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json);
+ parcJSON_Release(&json);
+ parcBuffer_Release(&payload);
+ return success;
+}
+
+/**
+ * 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
+ case CCNxCodecSchemaV1Types_MessageType_Manifest: // 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 if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Manifest) {
+ ccnxTlvDictionary_SetMessageType_Manifest(data->packetDictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ success = ccnxCodecSchemaV1ManifestDecoder_Decode(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;
+}
+
+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;
+}
+
+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;
+}
+
+bool
+ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary)
+{
+ bool decodeSuccess = false;
+
+ _CCNxCodecSchemaV1Data data;
+
+ // we temporarily store this reference, but we do not destroy it. This
+ // is just to pass the reference down the decode chain, it is not
+ // stored beyond the immediate scope. Therefore, no reference acquired.
+ data.packetDictionary = packetDictionary;
+ data.decoder = packetDecoder;
+
+ if (ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data.decoder, data.packetDictionary)) {
+ if (_decodeOptionalHeaders(&data)) {
+ // Record the position we'd start the signature verification at
+ size_t signatureStartPosition = ccnxCodecTlvDecoder_Position(data.decoder);
+
+
+ // Mark the beginning of the ContentObject hash region.
+ CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionStart(data.packetDictionary, signatureStartPosition);
+
+ if (_decodeMessage(&data)) {
+ // If there's anything else left, it must be the validation alg and payload
+ if (!ccnxCodecTlvDecoder_IsEmpty(data.decoder)) {
+ if (_decodeValidationAlg(&data)) {
+ // at this point, we've advanced to the end of the validation algorithm,
+ // that's where we would end signature verification
+ size_t signatureStopPosition = ccnxCodecTlvDecoder_Position(data.decoder);
+
+ CCNxWireFormatFacadeV1_Implementation.setProtectedRegionStart(data.packetDictionary, signatureStartPosition);
+ CCNxWireFormatFacadeV1_Implementation.setProtectedRegionLength(data.packetDictionary, signatureStopPosition - signatureStartPosition);
+
+ if (_decodeValidationPayload(&data)) {
+ decodeSuccess = true;
+ }
+ }
+ } else {
+ // nothing after the message, so that's a successful decode
+ decodeSuccess = true;
+ }
+
+ // Mark the length of the ContentObject hash region (to the end of the packet).
+ size_t contentObjectHashRegionLength = ccnxCodecTlvDecoder_Position(data.decoder) - signatureStartPosition;
+ CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionLength(data.packetDictionary, contentObjectHashRegionLength);
+ }
+ }
+ }
+
+ return decodeSuccess;
+}
+
+bool
+ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary)
+{
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, packetDictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ return success;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h
new file mode 100755
index 00000000..9c1defd9
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h
@@ -0,0 +1,91 @@
+/*
+ * 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 ccnxCodecSchemaV1_PacketDecoder.h
+ * @brief Decoder for the version 1 TLV Packet
+ *
+ * The Schema version 1 Dictionary is organized in containers: FixedHeader, OptionalHeaders, (Interest, ContentObject, Control), Verification.
+ *
+ * Each container is its own dictionary.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTlvDictionary *packetDictionary = ccnxTlvDictionary_Create();
+ * ccnxCodecSchemaV1PacketDecoder_Decode(packetBuffer, packetDictionary);
+ * // the fields in the packetDictionary are now set
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_PacketDecoder_h
+#define CCNxCodecSchemaV1_PacketDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+
+/**
+ * Decode a packet in to a dictionary.
+ *
+ * The buffer should be set at the start of the fixed header. This call is equivalent
+ * to ccnxCodecSchemaV1PacketDecoder_Decode(), except it allocates and destroys a temporary
+ * CCNxCodecTlvDecoder.
+ *
+ * The dictionary will be filled in with all fields available in the packetBuffer.
+ *
+ * Caveat: there is no way to find out where the error was if returned "false"
+ *
+ * @param [in] buffer The packet buffer
+ * @param [in] packetDictionary The dictionary to fill in
+ *
+ * @return true Successful decode
+ * @return false There was an error somewhere
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+bool ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Decode in to in to a dictionary.
+ *
+ * The buffer should be set at the start of the fixed header.
+ *
+ * The dictionary will be filled in with all fields available in the packetDecoder.
+ *
+ * Caveat: there is no way to find out where the error was if returned "false"
+ *
+ * @param [in] buffer The packet buffer
+ * @param [in] packetDictionary The dictionary to fill in
+ *
+ * @return true Successful decode
+ * @return false There was an error somewhere
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+bool ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // CCNxCodecSchemaV1_PacketDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
new file mode 100755
index 00000000..bddd32d4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
@@ -0,0 +1,353 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+
+// =====================================================
+// Private API
+
+static uint8_t
+_getHopLimit(CCNxTlvDictionary *packetDictionary)
+{
+ uint8_t hoplimit = (uint8_t) CCNxInterestDefault_HopLimit;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT)) {
+ hoplimit = (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT);
+ }
+ return hoplimit;
+}
+
+static uint8_t
+_getInterestReturnCode(CCNxTlvDictionary *packetDictionary)
+{
+ uint8_t returnCode = (uint8_t) 0;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode)) {
+ returnCode =
+ (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode);
+ }
+ return returnCode;
+}
+
+/**
+ * Creates a fixed header from the given parameters and encodes in network byte order
+ *
+ * All parameters in host byte order.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-negative The total bytes appended to the encode buffer
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static ssize_t
+_encodeFixedHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder,
+ CCNxTlvDictionary *packetDictionary,
+ int packetType,
+ ssize_t headerLength,
+ ssize_t packetLength)
+{
+ CCNxCodecSchemaV1FixedHeader fixedHeader;
+ memset(&fixedHeader, 0, sizeof(fixedHeader));
+
+ fixedHeader.version = 1;
+ fixedHeader.packetType = packetType;
+ fixedHeader.packetLength = packetLength;
+ fixedHeader.headerLength = headerLength;
+
+ if ((packetType == CCNxCodecSchemaV1Types_PacketType_Interest) ||
+ (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn)) {
+ CCNxCodecSchemaV1InterestHeader *interestHeader = (CCNxCodecSchemaV1InterestHeader *) &fixedHeader;
+ interestHeader->hopLimit = _getHopLimit(packetDictionary);
+ if (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn) {
+ interestHeader->returnCode = _getInterestReturnCode(packetDictionary);
+ }
+ }
+
+ return ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(fixedHeaderEncoder, &fixedHeader);
+}
+
+static ssize_t
+_encodeOptionalHeaders(CCNxCodecTlvEncoder *optionalHeaderEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ // Optional Headers do not have a container, so just append them right to the buffer
+ size_t optionalHeadersLength = 0;
+ optionalHeadersLength = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(optionalHeaderEncoder, packetDictionary);
+ return optionalHeadersLength;
+}
+
+/**
+ * CPI payload is simply a dump of the PAYLOAD dictionary entry.
+ *
+ * There are no inner TLVs of this message, so it is not encoded like a normal message
+ * with a call to ccnxCodecSchemaV1MessageEncoder_Encode(). Rather it is written here.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return non-negative The number of bytes appended to the buffer
+ * @return negative An error
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static ssize_t
+_encodeCPI(CCNxCodecTlvEncoder *cpiEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ // Optional Headers do not have a container, so just append them right to the buffer
+ size_t payloadLength = 0;
+
+ if (ccnxTlvDictionary_IsValueJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD)) {
+ PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (json) {
+ char *jsonString = parcJSON_ToCompactString(json);
+
+ payloadLength = strlen(jsonString);
+ ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, (uint8_t * ) jsonString);
+ parcMemory_Deallocate((void **) &jsonString);
+ }
+ } else {
+ PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+
+ payloadLength = parcBuffer_Remaining(payload);
+ uint8_t *overlay = parcBuffer_Overlay(payload, 0);
+ ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, overlay);
+ }
+ return payloadLength;
+}
+
+/**
+ * Encode the CCNx Message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [out] packetTypePtr The type to use for the PacketType based on the message type
+ *
+ * @retval non-negative the bytes appended to the encoder
+ * @retval negative An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static ssize_t
+_encodeMessage(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary, CCNxCodecSchemaV1Types_PacketType *packetTypePtr)
+{
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ ssize_t innerLength = -1;
+
+ // what kind of message is it? need this to set the packetTypePtr
+
+ if (ccnxTlvDictionary_IsInterest(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Interest;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_InterestReturn;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_ContentObject, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Control;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Control, 0);
+ innerLength = _encodeCPI(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Manifest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ }
+
+ if (innerLength >= 0) {
+ // For a 0 length message, we do not backup and erase the TLV container.
+ ccnxCodecTlvEncoder_SetContainerLength(packetEncoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ innerLength = endPosition - startPosition;
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(packetEncoder));
+ ccnxCodecTlvEncoder_SetError(packetEncoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return innerLength;
+}
+
+static ssize_t
+_encodeValidationAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t innerLength = 0;
+
+ // There must be a CryptoSuite in the packet to sign it.
+ // Temporary exception for Content Objects, which are all signed if the codec has a signer.
+ if (ccnxValidationFacadeV1_HasCryptoSuite(packetDictionary) || ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationAlg, 0);
+ innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, packetDictionary);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength >= 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ return endPosition - startPosition;
+ }
+ }
+
+ return innerLength;
+}
+
+static ssize_t
+_encodeValidationPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 0);
+ ssize_t innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, packetDictionary);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ return endPosition - startPosition;
+ }
+
+ return innerLength;
+}
+
+// =====================================================
+// Public API
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer)
+{
+ CCNxCodecNetworkBufferIoVec *outputBuffer = NULL;
+
+ CCNxCodecTlvEncoder *packetEncoder = ccnxCodecTlvEncoder_Create();
+
+ if (signer) {
+// ccnxCodecTlvEncoder_SetSigner(packetEncoder, signer);
+ }
+
+ ssize_t encodedLength = ccnxCodecSchemaV1PacketEncoder_Encode(packetEncoder, packetDictionary);
+ if (encodedLength > 0) {
+ ccnxCodecTlvEncoder_Finalize(packetEncoder);
+ outputBuffer = ccnxCodecTlvEncoder_CreateIoVec(packetEncoder);
+ }
+
+ trapUnexpectedStateIf(encodedLength < 0 && !ccnxCodecTlvEncoder_HasError(packetEncoder),
+ "Got error length but no error set");
+
+ assertFalse(ccnxCodecTlvEncoder_HasError(packetEncoder), "ENCODING ERROR")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(packetEncoder)));
+ ccnxTlvDictionary_Display(packetDictionary, 3);
+ }
+
+ ccnxCodecTlvEncoder_Destroy(&packetEncoder);
+
+ // return a reference counted copy so it won't be destroyed by ccnxCodecTlvEncoder_Destroy
+ return outputBuffer;
+}
+
+ssize_t
+ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = -1;
+
+ // We will need to go back and fixedup the headers
+ ssize_t fixedHeaderPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ ssize_t fixedHeaderLength = _encodeFixedHeader(packetEncoder, packetDictionary, -1, 0, 0);
+
+ ssize_t optionalHeadersLength = _encodeOptionalHeaders(packetEncoder, packetDictionary);
+
+ if (optionalHeadersLength >= 0) {
+ ccnxCodecTlvEncoder_MarkSignatureStart(packetEncoder);
+
+ CCNxCodecSchemaV1Types_PacketType messageType = -1;
+
+ ssize_t messageLength = _encodeMessage(packetEncoder, packetDictionary, &messageType);
+
+ if (messageLength >= 0) {
+ // validation is optional, so it's ok if its 0 length
+ ssize_t validationAlgLength = _encodeValidationAlg(packetEncoder, packetDictionary);
+ ssize_t validationPayloadLength = 0;
+ if (validationAlgLength > 0) {
+ ccnxCodecTlvEncoder_MarkSignatureEnd(packetEncoder);
+
+ validationPayloadLength = _encodeValidationPayload(packetEncoder, packetDictionary);
+ }
+
+ if (validationAlgLength >= 0 && validationPayloadLength >= 0) {
+ // now fix up the fixed header
+ size_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+
+ size_t headerLength = fixedHeaderLength + optionalHeadersLength;
+ size_t packetLength = headerLength + messageLength + validationAlgLength + validationPayloadLength;
+
+ // Will this work for InterestReturn? As long as _encodeMessage returns InterestReturn it
+ // will be ok.
+ int packetType = messageType;
+
+ ccnxCodecTlvEncoder_SetPosition(packetEncoder, fixedHeaderPosition);
+ _encodeFixedHeader(packetEncoder, packetDictionary, packetType, headerLength, packetLength);
+ ccnxCodecTlvEncoder_SetPosition(packetEncoder, endPosition);
+ length = endPosition - fixedHeaderPosition;
+
+ trapUnexpectedStateIf(packetLength != length, "packet length %zu not equal to measured length %zd", packetLength, length);
+ }
+ }
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h
new file mode 100755
index 00000000..c83f165f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h
@@ -0,0 +1,85 @@
+/*
+ * 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 ccnxCodecSchemaV1_PacketEncoder.h
+ * @brief Encoder for the version 1 TLV Packet
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_PacketEncoder_h
+#define CCNxCodecSchemaV1_PacketEncoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+/**
+ * Encode the packetDictionary to wire format
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1",
+ * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * The signer is not stored beyond the call to DictionaryEncode.
+ * If the dictionary already has a ValidationAlg and ValidationPayload, those are used, not the Signer.
+ * Otherwise, if the signer is not null, it is used to sign the wire format.
+ *
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ * @param [in] signer If not NULL will be used to sign the wire format
+ *
+ * @retval non-null An IoVec that can be written to the network
+ * @retval null an error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer);
+
+/**
+ * Encode a packetDictionary to wire format.
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1",
+ * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * You must use ccnxCodecTlvEncoder_SetSigner(signer) if you require a signature or MAC on the packet.
+ *
+ * @param [in] packetEncoder A TLV packet will be appended to the encoder
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ *
+ * @retval non-negative The total bytes appended to the encode buffer
+ * @retval -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // CCNxCodecSchemaV1_PacketEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c
new file mode 100644
index 00000000..72e1ce3e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c
@@ -0,0 +1,68 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/runtime.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateInterest(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateManifest(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Manifest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateControl(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Control(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h
new file mode 100755
index 00000000..e76492b6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h
@@ -0,0 +1,250 @@
+/*
+ * 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 ccnxCodecSchemaV1_TlvDictionary.h
+ * @brief <#Brief Description#>
+ *
+ * Used as keys to the CCNxTlvDictionary for the version 1 schema
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvDictionary_SchemaV1_h
+#define libccnx_ccnx_TlvDictionary_SchemaV1_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * @typedef CCNxCodecSchemaV1TlvDictionary_CryptoSuite
+ * @abstract The ValidationAlgorithm Type.
+ * @constant <#name#> <#description#>
+ * @discussion These are the wire-format values for the ValidationAlgorithm type. The values
+ * specified follow from the CCNx Messages RFC.
+ *
+ * It is not the same as the value stored in CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE,
+ * which is of type PARCCryptoSuite.
+ */
+typedef enum rta_tlv_schema_v1_crypto_suite {
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C = 2,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256 = 4,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256 = 6,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1 = 7,
+} CCNxCodecSchemaV1TlvDictionary_CryptoSuite;
+
+/**
+ * @typedef <#CCNBHeaderType#>
+ * @abstract <#Abstract#>
+ * @constant CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat The off-the-wire packet or a pre-encoded packet
+ * @discussion
+ * The WireFormat header is a ficticious header for holding the off-the-wire packet received
+ * from the network or to send a pre-encoded packet down through the stack.
+ *
+ * The Forwarder header is a ficticious header for holding special forwarder control block. The
+ * forwarder control block, on ingress, contains information about where a packet arrived. On
+ * egress, it contains information about how the packet should be transmitted, such as restricting
+ * it to a specific egress interface.
+ *
+ * The protected region extent is used to determine they byte range used for verification.
+ */
+
+
+typedef enum rta_tlv_schema_v1_headers_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_TransportStack = 0, /**< Array element 0 is used by RTA Transport stack */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader = 1,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG = 2,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG = 3,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat = 4,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_Forwarder = 5,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime = 6,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime = 7,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart = 8, /**< Fictitious header for Protected Region Extent */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength = 9, /**< Fictitious header for Protected Region length */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart = 10, /**< Fictitious header for CO Hash Region Extent */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength = 11, /**< Fictitious header for CO Hash Region length */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode = 12,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = 13,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END = 14
+} CCNxCodecSchemaV1TlvDictionary_HeadersFastArray;
+
+/**
+ * The ValidationFastArray are fields that may appear in the Validation Algorithm and the Validation Payload field.
+ *
+ * Note that the ValidationFastArray_CRYPTO_SUITE is always expressed in terms of PARCCryptoSuite.
+ */
+typedef enum rta_tlv_schema_v1_validation_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 0,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 1, // PARCCryptoSuite value
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 2,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 3,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 4,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 5,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 6,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 7,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 8,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 9
+} CCNxCodecSchemaV1TlvDictionary_ValidationFastArray;
+
+
+/**
+ * The MessageFastArray are fields that may appear in the body of a CCNx message (Interest, Content Object, Control).
+ *
+ * The Hop Limit is part of the MessageFastArray even though it appears in the FixedHeader. It is treated like a property
+ * of the Interest.
+ */
+typedef enum rta_tlv_schema_v1_message_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 0,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 1,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 2,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 4,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 5, /***< Virtual field */
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 6,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 7,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 8,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HASH_GROUP = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 9,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_DATA_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 10,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_MANIFEST_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 11,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 12
+} CCNxCodecSchemaV1TlvDictionary_MessageFastArray;
+
+//const int CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END + 1;
+
+/**
+ * Each TLV container can have custom types in it, so each container has a "list"
+ * Organization Extensions go here.
+ */
+typedef enum rta_tlv_schema_v1_lists {
+ CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS = 0,
+ CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST = 1,
+ CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST = 4,
+ CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_PAYLOAD_LIST = 5,
+ CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST = 6,
+ CCNxCodecSchemaV1TlvDictionary_Lists_END = 7
+} CCNxCodecSchemaV1TlvDictionary_Lists;
+
+/**
+ * Creates an empty Interest dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Interest. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Interest
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Interest) {
+ * CCNxTlvDictionary *interest = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ * // decode the rest of the packet
+ * return interest;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterest(void);
+
+/**
+ * Creates an empty Content Object dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Content Object. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Content Object
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_ContentObject) {
+ * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ * // decode the rest of the packet
+ * return object;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void);
+
+/**
+ * Creates an empty Manifest dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Content Object. The
+ * PayloadType will be set to CCNxPayloadType_MANIFEST. No other fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Manifest
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Manifest) {
+ * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_Manifest();
+ * // decode the rest of the packet
+ * return object;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateManifest(void);
+
+/**
+ * Creates an empty Control dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Control. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Control
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Control) {
+ * CCNxTlvDictionary *control = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ * // decode the rest of the packet
+ * return control;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateControl(void);
+
+/**
+ * Creates an empty InterestReturn dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be InterestReturn. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type InterestReturn
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_InterestReturn) {
+ * CCNxTlvDictionary *interestReturn = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ * // decode the rest of the packet
+ * return interestReturn;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void);
+#endif // libccnx_ccnx_TlvDictionary_SchemaV1_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h
new file mode 100755
index 00000000..1c50eebc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h
@@ -0,0 +1,211 @@
+/*
+ * 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 ccnxCodecSchemaV1_Types.h
+ * @brief Common definitions for Schema version 1
+ *
+ * Defines the TLV "type" values for each field
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_Types_h
+#define TransportRTA_ccnxCodecSchemaV1_Types_h
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_PacketType
+ * @abstract The values used in the PacketType field of the Fixed Header
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_packet_type {
+ CCNxCodecSchemaV1Types_PacketType_Interest = 0x00,
+ CCNxCodecSchemaV1Types_PacketType_ContentObject = 0x01,
+ CCNxCodecSchemaV1Types_PacketType_InterestReturn = 0x02,
+ CCNxCodecSchemaV1Types_PacketType_Control = 0xA4,
+} CCNxCodecSchemaV1Types_PacketType;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_MessageType
+ * @abstract The values used in the MessageType field of the CCNx Message body
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_message_type {
+ CCNxCodecSchemaV1Types_MessageType_Interest = 0x0001,
+ CCNxCodecSchemaV1Types_MessageType_ContentObject = 0x0002,
+ CCNxCodecSchemaV1Types_MessageType_ValidationAlg = 0x0003,
+ CCNxCodecSchemaV1Types_MessageType_ValidationPayload = 0x0004,
+ CCNxCodecSchemaV1Types_MessageType_Manifest = 0x0006,
+ CCNxCodecSchemaV1Types_MessageType_Control = 0xBEEF,
+} CCNxCodecSchemaV1Types_MessageType;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_OptionalHeadersTypes
+ * @abstract The well-known keys for the hop-by-hop headers
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_optional_headers_types {
+ CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime = 0x0001,
+ CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime = 0x0002,
+ CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel = 0x0003,
+ CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment = 0x0004,
+ CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment = 0x0005,
+} CCNxCodecSchemaV1Types_OptionalHeaders;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_PayloadType
+ * @abstract The values of the PayloadType field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_payloadtype_types {
+ CCNxCodecSchemaV1Types_PayloadType_Data = 0,
+ CCNxCodecSchemaV1Types_PayloadType_Key = 1,
+ CCNxCodecSchemaV1Types_PayloadType_Link = 2,
+} CCNxCodecSchemaV1Types_PayloadType;
+
+// ==================================================
+// Fields in a Message Object
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_MessageTypes
+ * @abstract The well-known types inside the CCNxMessage
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_ccnxmessage_types {
+ CCNxCodecSchemaV1Types_CCNxMessage_Name = 0x0000,
+ CCNxCodecSchemaV1Types_CCNxMessage_Payload = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction = 0x0003,
+ CCNxCodecSchemaV1Types_CCNxMessage_PayloadType = 0x0005,
+ CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime = 0x0006,
+ CCNxCodecSchemaV1Types_CCNxMessage_HashGroup = 0x0007,
+ CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber = 0x0019,
+} CCNxCodecSchemaV1Types_CCNxMessage;
+
+typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_types {
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer = 0x0003,
+} CCNxCodecSchemaV1Types_CCNxManifestHashGroup;
+
+typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_metadata_types {
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator = 0x0000,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize = 0x0003,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight = 0x0004,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256 = 0x0005,
+} CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata;
+
+// ==================================================
+// Fields in a Validation Algorithm
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_ValidationAlg
+ * @abstract The well-known keys for the ContentObject
+ * @constant <#name#> <#description#>
+ * @discussion the CCNxCodecSchemaV1Types_ValidationAlg values for the crypto suites must be the same as CCNxCodecSchemaV1Types_CryptoSuiteType
+ */
+typedef enum rta_tlv_schema_v1_validation_alg {
+ CCNxCodecSchemaV1Types_ValidationAlg_CRC32C = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, // 0x0002
+ CCNxCodecSchemaV1Types_ValidationAlg_HMAC_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, // 0x0004
+ CCNxCodecSchemaV1Types_ValidationAlg_RSA_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, // 0x0006
+ CCNxCodecSchemaV1Types_ValidationAlg_EC_SECP_256K1 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, // 0x0007
+
+ CCNxCodecSchemaV1Types_ValidationAlg_KeyId = 0x0009,
+ CCNxCodecSchemaV1Types_ValidationAlg_PublicKey = 0x000B,
+ CCNxCodecSchemaV1Types_ValidationAlg_Cert = 0x000C,
+ CCNxCodecSchemaV1Types_ValidationAlg_KeyName = 0x000E,
+ CCNxCodecSchemaV1Types_ValidationAlg_SigTime = 0x000F,
+} CCNxCodecSchemaV1Types_ValidationAlg;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_Link
+ * @abstract The well-known keys for the LINK body
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_types {
+ CCNxCodecSchemaV1Types_Link_Name = 0x0000,
+ CCNxCodecSchemaV1Types_Link_KeyIdRestriction = 0x0001,
+ CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction = 0x0002,
+} CCNxCodecSchemaV1Types_Link;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashGroup
+ * @abstract The well-known keys for the Manifest HashGroup.
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_hash_group {
+ CCNxCodecSchemaV1Types_HashGroup_Metadata = 0x0001,
+ CCNxCodecSchemaV1Types_HashGroup_DataPointer = 0x0002,
+ CCNxCodecSchemaV1Types_HashGroup_ManifestPointer = 0x0003
+} CCNxCodecSchemaV1Types_HashGroup;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashGroup
+ * @abstract The well-known keys for the Manifest HashGroup.
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_hash_group_metadata {
+ CCNxCodecSchemaV1Types_HashGroup_Locator = 0x0000,
+ CCNxCodecSchemaV1Types_HashGroup_ExternalMetadata = 0x0001,
+ CCNxCodecSchemaV1Types_HashGroup_BlockSize = 0x0002,
+ CCNxCodecSchemaV1Types_HashGroup_OverallDataSize = 0x0003,
+ CCNxCodecSchemaV1Types_HashGroup_OverallDataSha256 = 0x0004,
+} CCNxCodecSchemaV1Types_HashGroupMetadata;
+
+// ==================================================
+// Interest Return
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_InterestReturnCode
+ * @abstract The values of the InterestReturn ReturnCode field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_interestreturncode_types {
+ CCNxCodecSchemaV1Types_InterestReturnCode_NoRoute = 0x01,
+ CCNxCodecSchemaV1Types_InterestReturnCode_HopLimitExceeded = 0x02,
+ CCNxCodecSchemaV1Types_InterestReturnCode_NoResources = 0x03,
+ CCNxCodecSchemaV1Types_InterestReturnCode_PathError = 0x04,
+ CCNxCodecSchemaV1Types_InterestReturnCode_Prohibited = 0x05,
+ CCNxCodecSchemaV1Types_InterestReturnCode_Congestion = 0x06,
+ CCNxCodecSchemaV1Types_InterestReturnCode_MTUTooLarge = 0x07,
+} CCNxCodecSchemaV1Types_InterestReturnCode;
+
+// ==================================================
+// Hash function types
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashTypes
+ * @abstract The values of the InterestReturn ReturnCode field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_hash_types {
+ CCNxCodecSchemaV1Types_HashType_SHA256 = 0x01,
+ CCNxCodecSchemaV1Types_HashType_SHA512 = 0x02,
+ CCNxCodecSchemaV1Types_HashType_App
+} CCNxCodecSchemaV1Types_HashType;
+
+#endif //TransportRTA_ccnxCodecSchemaV1_Types_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c
new file mode 100755
index 00000000..0524bcfa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c
@@ -0,0 +1,176 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+static bool
+_decodeKeyName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ // At this point, the decoder should point to the 1st byte of the "value" of the (type, length) continer.
+ // This is defined as a CCNxLink
+
+ bool success = false;
+
+ // this will set the decoder error if it fails.
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, length);
+ if (link != NULL) {
+ const CCNxName *name = ccnxLink_GetName(link);
+ if (name != NULL) {
+ success = ccnxTlvDictionary_PutName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name);
+
+ if (success) {
+ PARCBuffer *keyid = ccnxLink_GetKeyID(link);
+ if (keyid) {
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID, keyid);
+ }
+
+ PARCBuffer *hash = ccnxLink_GetContentObjectHash(link);
+ if (hash) {
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH, hash);
+ }
+ }
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ ccnxLink_Release(&link);
+ }
+
+ return success;
+}
+
+static bool
+_decodeAlgParametersType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_ValidationAlg_Cert:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_KeyId:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_KeyName:
+ // The "value" is a link
+ success = _decodeKeyName(decoder, packetDictionary, type, length);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_SigTime:
+ // This is a time, so put it as an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_PublicKey:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ 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, CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST);
+ }
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/**
+ * Called by _decodeAlgType() via ccnxCodecTlvUtilities_DecodeSubcontainer() to decode the
+ * algorithm specific parameters
+ */
+static bool
+_decodeAlgParameters(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgParametersType);
+}
+
+static bool
+_decodeAlgType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+
+ PARCCryptoSuite parcSuite;
+ bool match = ccnxCodecSchemaV1CryptoSuite_TlvToParc((CCNxCodecSchemaV1TlvDictionary_CryptoSuite) type, &parcSuite);
+
+ if (match) {
+ success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, parcSuite);
+
+ if (success) {
+ success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, _decodeAlgParameters);
+ }
+ } else {
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST);
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+// ==================
+// Public API
+
+bool
+ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgType);
+}
+
+
+bool
+ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ bool success = false;
+ // A 0-length payload is treaded like an error
+ size_t remaining = ccnxCodecTlvDecoder_Remaining(decoder);
+ if (remaining > 0) {
+ PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(decoder, remaining);
+ success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, payload);
+ parcBuffer_Release(&payload);
+ }
+ return success;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h
new file mode 100755
index 00000000..c5d5a42c
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h
@@ -0,0 +1,74 @@
+/*
+ * 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 ccnxCodecSchemaV1_ValidationDecoder.h
+ * @brief Decode the validation algorithm and payload
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__
+#define __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode the validation algorithm
+ *
+ * The decoder should point to byte 0 of the valdiation algorithm "value"
+ *
+ * The results are put in the provided dictionary.
+ * It is an error if the "value" does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * The decode the validation payload
+ *
+ * The decoder should point to byte 0 of the valdiation payload "value"
+ * The payload is an opaque block, so this function will just put the "value" in to the proper
+ * dictionary location. There's no real parsing.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c
new file mode 100755
index 00000000..f7ad00aa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c
@@ -0,0 +1,253 @@
+/*
+ * 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 <config.h>
+#include <sys/time.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+static ssize_t
+_encodeKeyId(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ if (keyid) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyId, keyid);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePublicKey(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *key = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ if (key) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_PublicKey, key);
+ }
+ return length;
+}
+
+static ssize_t
+_encodeCertificate(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *cert = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ if (cert) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_Cert, cert);
+ }
+ return length;
+}
+
+/**
+ * If there is a CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME entry in the dictionary, look up the
+ * optional keyid and hash restrictions, create a CCNxLink, then encode the Link.
+ */
+static ssize_t
+_encodeKeyName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ CCNxName *keyname = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ if (keyname) {
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ PARCBuffer *hash = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+ CCNxLink *link = ccnxLink_Create(keyname, keyid, hash);
+
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyName, 0);
+ ssize_t innerLength = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ length = endPosition - startPosition;
+ } else {
+ // an error signal
+ length = innerLength;
+ }
+
+ ccnxLink_Release(&link);
+ }
+ return length;
+}
+
+/**
+ * If a time is not provided, use the current time
+ */
+static ssize_t
+_encodeSignatureTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ bool haveSignTime = false;
+ uint64_t signTime = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME)) {
+ haveSignTime = true;
+ signTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ } else {
+ // if we have a signer and with a signature algorithm, create the signing time
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer) {
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ if (alg != PARCSigningAlgortihm_NULL && alg != PARCSigningAlgorithm_UNKNOWN) {
+ // We will generate a signature, so generate a signing time
+
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ // convert to milli-seconds
+ signTime = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ haveSignTime = true;
+ }
+ }
+ }
+
+ if (haveSignTime) {
+ length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_ValidationAlg_SigTime, signTime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeAlgParameters(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeKeyId(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePublicKey(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeCertificate(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeKeyName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeSignatureTime(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ bool haveCryptoSuite = false;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite suite;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ // try from dictionary
+
+ PARCCryptoSuite parcSuite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+
+ haveCryptoSuite = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(parcSuite, &suite);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ // deduce from the signer
+
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer != NULL) {
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ PARCSigningAlgorithm signAlg = parcSigner_GetSigningAlgorithm(signer);
+
+ if (ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(signAlg, hashType, &suite)) {
+ haveCryptoSuite = true;
+ }
+ }
+ }
+
+ if (haveCryptoSuite) {
+ // write the TL container then encode any enclosed TLVs
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, suite, 0);
+ ssize_t innerLength = _encodeAlgParameters(encoder, packetDictionary);
+
+ // 0 inner length is acceptable
+ if (innerLength >= 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ length = endPosition - startPosition;
+ } else {
+ // an error signal
+ length = innerLength;
+ }
+ }
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ if (!ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD)) {
+ // try to compute a signature
+
+ // If signer is NULL, then no signature is genearted
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer != NULL) {
+ // user did not give us one, so fill it in
+ PARCSignature *signature = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ PARCBuffer *sigbits = parcSignature_GetSignature(signature);
+
+ // this creates its own reference to sigbits
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, sigbits);
+
+ // this will release our hold on sigbitsElastic and sigbits.
+ parcSignature_Release(&signature);
+ }
+ }
+
+ PARCBuffer *sigbits = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ if (sigbits) {
+ size_t remaining = parcBuffer_Remaining(sigbits);
+ uint8_t *overlay = parcBuffer_Overlay(sigbits, 0);
+ length = ccnxCodecTlvEncoder_AppendRawArray(encoder, remaining, overlay);
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h
new file mode 100755
index 00000000..3897a053
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h
@@ -0,0 +1,79 @@
+/*
+ * 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 ccnxCodecSchemaV1_ValidationEncoder.h
+ * @brief Encode the Validation Algorithm and Payload
+ *
+ * Encodes the validation algorithm and payload from the dictionary. Optionally computes
+ * a signature if one is not specified in the dictionary and the encoder has a signer.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__
+#define __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+/**
+ * Appends the Validation Algorithm to the packet encoder
+ *
+ * If the dictionary has a CryptoSuite specified, we will create a ValidationAlgorithm section
+ * and fill it in as per the CryptoSuite and supplied validation algorithm arguments, such as
+ * a KeyId, KeyName, Cert, etc. For most signatures, only the KeyId is mandatory, the other
+ * fields will only be specified if the user put something in the dictionary.
+ *
+ * the caller is responsible for writing the ValidationAlgorithm TL container.
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Appends the Validation Payload to the packet encoder
+ *
+ * This will append the Valdiation Payload from the dictionary, or if it is missing and the
+ * encoder has a signer, will create a signature.
+ *
+ * the caller is responsible for writing the ValidationPayload TL container.
+ *
+ * To create the signature, the caller must have used ccnxCodecTlvEncoder_MarkSignatureStart() and
+ * ccnxCodecTlvEncoder_MarkSignatureEnd() functions to specify the byte locations of the start and
+ * stop of the protected region.
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore
new file mode 100644
index 00000000..ffeaadf8
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore
@@ -0,0 +1,19 @@
+*.gcno
+*.log
+*.trs
+*.o
+test_ccnxCodecSchemaV1_CryptoSuite
+test_ccnxCodecSchemaV1_FixedHeaderDecoder
+test_ccnxCodecSchemaV1_FixedHeaderEncoder
+test_ccnxCodecSchemaV1_LinkCodec
+test_ccnxCodecSchemaV1_MessageDecoder
+test_ccnxCodecSchemaV1_MessageEncoder
+test_ccnxCodecSchemaV1_NameCodec
+test_ccnxCodecSchemaV1_NameSegmentCodec
+test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+test_ccnxCodecSchemaV1_PacketDecoder
+test_ccnxCodecSchemaV1_PacketEncoder
+test_ccnxCodecSchemaV1_TlvDictionary
+test_ccnxCodecSchemaV1_ValidationDecoder
+test_ccnxCodecSchemaV1_ValidationEncoder
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt
new file mode 100644
index 00000000..c827a36e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnxCodecSchemaV1_CryptoSuite
+ test_ccnxCodecSchemaV1_FixedHeaderDecoder
+ test_ccnxCodecSchemaV1_FixedHeaderEncoder
+ test_ccnxCodecSchemaV1_HashCodec
+ test_ccnxCodecSchemaV1_LinkCodec
+ test_ccnxCodecSchemaV1_ManifestDecoder
+ test_ccnxCodecSchemaV1_ManifestEncoder
+ test_ccnxCodecSchemaV1_MessageDecoder
+ test_ccnxCodecSchemaV1_MessageEncoder
+ test_ccnxCodecSchemaV1_NameCodec
+ test_ccnxCodecSchemaV1_NameSegmentCodec
+ test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+ test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+ test_ccnxCodecSchemaV1_PacketDecoder
+ test_ccnxCodecSchemaV1_PacketEncoder
+ test_ccnxCodecSchemaV1_TlvDictionary
+ test_ccnxCodecSchemaV1_ValidationDecoder
+ test_ccnxCodecSchemaV1_ValidationEncoder
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c
new file mode 100644
index 00000000..10bc24d2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c
@@ -0,0 +1,154 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_CryptoSuite.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_CryptoSuite)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_CryptoSuite)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv)
+{
+ struct test_vector {
+ PARCCryptoSuite input;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite output;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .input = PARCCryptoSuite_RSA_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_HMAC_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_NULL_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_DSA_SHA256, .output = 0, .success = false, .sentinel = false },
+ { .input = PARCCryptoSuite_RSA_SHA512, .output = 0, .success = false, .sentinel = false },
+ { .input = PARCCryptoSuite_HMAC_SHA512, .output = 0, .success = false, .sentinel = false },
+ { .input = 13579, .output = 0, .success = false, .sentinel = false },
+ { .input = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(vectors[i].input, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc)
+{
+ struct test_vector {
+ PARCCryptoSuite output;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite input;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .output = PARCCryptoSuite_RSA_SHA256, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .output = PARCCryptoSuite_HMAC_SHA256, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .output = PARCCryptoSuite_NULL_CRC32C, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, .output = 0, .success = false, .sentinel = false },
+ { .input = 13579, .output = 0, .success = false, .sentinel = false },
+ { .input = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_TlvToParc(vectors[i].input, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv)
+{
+ struct test_vector {
+ PARCSigningAlgorithm signAlg;
+ PARCCryptoHashType hashType;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite output;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .signAlg = PARCSigningAlgorithm_RSA, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgortihm_NULL, .hashType = PARCCryptoHashType_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_RSA, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = PARCSigningAlgortihm_NULL, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = 12345, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = 0, .hashType = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(vectors[i].signAlg, vectors[i].hashType, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_CryptoSuite);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c
new file mode 100644
index 00000000..7a889b58
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c
@@ -0,0 +1,350 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_FixedHeaderDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ uint8_t *packet;
+ PARCBuffer *fixedHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t hopLimit;
+ uint8_t returnCode;
+ uint8_t flags;
+ uint8_t headerLength;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->packet = parcMemory_Allocate(8);
+ assertNotNull(data->packet, "parcMemory_Allocate(%d) returned NULL", 8);
+ memcpy(data->packet, &((uint8_t[]) { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08 }), 8);
+
+ data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8);
+ data->version = 0;
+ data->packetType = 1;
+ data->packetLength = 0x0102;
+ data->hopLimit = 3;
+ data->returnCode = 4;
+ data->flags = 5;
+ data->headerLength = 8;
+ data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader);
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+// TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->fixedHeader);
+ parcMemory_Deallocate((void **) &(data->packet));
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * Successful decode is tested in all the _GetX functions. We only test
+ * when the buffer is too small here
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ // advance the buffer so its too small
+ ccnxCodecTlvDecoder_Advance(data->decoder, 1);
+
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(data->decoder);
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(data->decoder);
+
+ assertFalse(success, "Should have failed with too small a buffer");
+ assertTrue(beforePosition == afterPosition, "Wrong postion, got %zu expected %zu", afterPosition, beforePosition);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary);
+ assertTrue(headerLength == data->headerLength, "Wrong headerLength, got %d expected %d", headerLength,
+ data->headerLength);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int packetType = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary);
+ assertTrue(packetType == data->packetType, "Wrong packetType, got %d expected %d", packetType, data->packetType);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int packetLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary);
+ assertTrue(packetLength == data->packetLength, "Wrong payloadLength, got %d expected %d", packetLength,
+ data->packetLength);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int hopLimit = ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(data->dictionary);
+ assertTrue(hopLimit == data->hopLimit, "Wrong hopLimit, got %d expected %d", hopLimit, data->hopLimit);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int returnCode = ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(data->dictionary);
+ assertTrue(returnCode == data->returnCode, "Wrong returnCode, got %d expected %d", returnCode, data->returnCode);
+
+ // Check that the InterestReturnCode was set in the fast array, too.
+ uint8_t test =
+ ccnxTlvDictionary_GetInteger(data->dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode);
+ assertTrue(test == data->returnCode, "Expected the dictionary to have the return code set");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int flags = ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(data->dictionary);
+ assertTrue(flags == data->flags, "Wrong flags, got %d expected %d", flags, data->flags);
+}
+
+
+// ==============================
+// Tests for missing values
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary);
+ assertTrue(version == -1, "Wrong HeaderLength, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary);
+ assertTrue(version == -1, "Wrong PacketType, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary);
+ assertTrue(version == -1, "Wrong payloadLength, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == -1, "Wrong version, got %d expected %d", version, -1);
+}
+
+
+/**
+ * Packet length must be at least 8 bytes
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(3),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on packet length too short");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+/**
+ * Header length must be at least 8 bytes
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(12),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 6,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on header length too short");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+/**
+ * Packet length must be no less than Header Length
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(12),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 18,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on packet length less than header length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+// ======================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_FixedHeaderDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c
new file mode 100755
index 00000000..4f479090
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c
@@ -0,0 +1,174 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_FixedHeaderEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/test/testrig_Compare.c>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = packetLength,
+ .hopLimit = 4,
+ .returnCode = 7, // will be set to 0
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(packetLength),
+ .hopLimit = 4,
+ .returnCode = 0,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject,
+ .packetLength = packetLength,
+ .hopLimit = 4, // will be set to 0
+ .returnCode = 7, // will be set to 0
+ .flags = 8, // will be set to 0
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject,
+ .packetLength = htons(packetLength),
+ .hopLimit = 0,
+ .returnCode = 0,
+ .flags = 0,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn,
+ .packetLength = packetLength,
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn,
+ .packetLength = htons(packetLength),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_FixedHeaderEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c
new file mode 100644
index 00000000..9d03ca2e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c
@@ -0,0 +1,235 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_HashCodec.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Hash)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Hash)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 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 *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *payloadBuffer = parcBuffer_Wrap(encoded + 4, sizeof(encoded) - 4, 0, sizeof(encoded) - 4);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(hash, "got non-NULL hash when it should have been an error (null)");
+
+ assertTrue(parcCryptoHash_GetDigestType(hash) == PARCCryptoHashType_SHA256, "Expected to decode the correct hash type.");
+ assertTrue(parcBuffer_Equals(payloadBuffer, parcCryptoHash_GetDigest(hash)), "Expected the digest to match.");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNull(error, "Got null error when it should have been set");
+
+ parcCryptoHash_Release(&hash);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+ parcBuffer_Release(&payloadBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, 0xFF, 0x00, 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 *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded an incorrect hash digest");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x18,
+ 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 *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded a SHA256 hash digest with an incorrect length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA512, 0x00, 0x18,
+ 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 *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded a SHA512 hash digest with an incorrect length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_App, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,0x00,0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(hash, "Should have decoded an application hash digest with an arbitrary length");
+
+ parcCryptoHash_Release(&hash);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode)
+{
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 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 *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ // Create the hash
+ PARCBuffer *payloadBuffer = parcBuffer_Allocate(0x20);
+ PARCCryptoHash *expectedHash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, payloadBuffer);
+
+ // Encode it
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1HashCodec_Encode(encoder, expectedHash);
+ assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length);
+
+ // Check for equality
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "The hash was encoded incorrectly.")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoding, 3);
+ printf("Got\n");
+ parcBuffer_Display(testEncoding, 3);
+ }
+
+ parcBuffer_Release(&testEncoding);
+ parcBuffer_Release(&trueEncoding);
+
+ parcCryptoHash_Release(&expectedHash);
+ parcBuffer_Release(&payloadBuffer);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Hash);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c
new file mode 100755
index 00000000..599e3a5a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c
@@ -0,0 +1,450 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_LinkCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly)
+{
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope");
+
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ const CCNxName *test = ccnxLink_GetName(link);
+ assertTrue(ccnxName_Equals(truth, test), "Wrong name")
+ {
+ printf("Expected\n");
+ ccnxName_Display(truth, 3);
+ printf("Got\n");
+ ccnxName_Display(test, 3);
+ }
+
+ PARCBuffer *testKeyid = ccnxLink_GetKeyID(link);
+ assertNull(testKeyid, "Got a keyid without the wire encoding for it");
+
+ PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link);
+ assertNull(testHash, "got a hash without the wire encoding for it");
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+ ccnxName_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields)
+{
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope");
+
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ const CCNxName *test = ccnxLink_GetName(link);
+ assertTrue(ccnxName_Equals(truth, test), "Wrong name")
+ {
+ printf("Expected\n");
+ ccnxName_Display(truth, 3);
+ printf("Got\n");
+ ccnxName_Display(test, 3);
+ }
+
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24);
+ PARCBuffer *testKeyid = ccnxLink_GetKeyID(link);
+ assertTrue(parcBuffer_Equals(keyid, testKeyid), "Wrong keyid")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(testKeyid, 3);
+ }
+
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44);
+ PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link);
+ assertTrue(parcBuffer_Equals(hash, testHash), "Wrong hash")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(hash, 3);
+ printf("Got\n");
+ parcBuffer_Display(testHash, 3);
+ }
+
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+ ccnxName_Release(&truth);
+}
+
+/*
+ * wire format missing name
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName)
+{
+ uint8_t encoded[] = {
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+/*
+ * Wire format has an extra TLV in it that's not part of the spec
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- extra
+ 0x00, 0xFF, 0x00, 4,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun)
+{
+ // name length is beyond end of fragment
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 30,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun)
+{
+ // buffer is too short to even parse the T and L
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ // the "2" makes it too short to parse
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, 2);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+// ============
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ CCNxName *trueName = ccnxName_CreateFromCString("lci:/3=rope");
+ PARCBuffer *trueKeyId = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24);
+ PARCBuffer *trueHash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44);
+ PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxLink *link = ccnxLink_Create(trueName, trueKeyId, trueHash);
+
+ // now encode it and compare the the trueEncoding
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link);
+ assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "Wrong hash")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoding, 3);
+ printf("Got\n");
+ parcBuffer_Display(testEncoding, 3);
+ }
+
+ parcBuffer_Release(&testEncoding);
+ parcBuffer_Release(&trueEncoding);
+ parcBuffer_Release(&trueHash);
+ parcBuffer_Release(&trueKeyId);
+ ccnxName_Release(&trueName);
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c
new file mode 100755
index 00000000..3c1609ab
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c
@@ -0,0 +1,267 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ManifestDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode)
+{
+ 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();
+
+ bool result = ccnxCodecSchemaV1ManifestDecoder_Decode(decoder, dict);
+ assertTrue(result, "Expected the manifest to be decoded correctly");
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&wireFormat);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c
new file mode 100755
index 00000000..a0e36abf
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c
@@ -0,0 +1,306 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ManifestEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("lci:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+
+ assertTrue(result == 0, "Expected an empty Manifest to be encoded to size 0, got %zu", result);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+ size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base + 8, parcBuffer_Overlay(pointer, parcBuffer_Remaining(pointer)), vector->iov_len - 8) == 0, "Expected the same pointer to be encoded");
+
+ uint16_t expectedType = CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer;
+ uint8_t *base = (uint8_t *) vector->iov_base;
+ uint16_t actualType = (base[4] << 8) | base[5];
+ assertTrue(expectedType == actualType, "Expected the type to be written correctly as CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ ccnxManifestHashGroup_Release(&group);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+ size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ uint8_t expectedVector[24] = { 0x00, 0x07, 0x00, 0x14,
+ 0x00, 0x02, 0x00, 0x10,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF };
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same pointer to be encoded");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ ccnxManifestHashGroup_Release(&group);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ // Set the metadata now
+ CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator");
+ ccnxManifestHashGroup_SetLocator(group, groupLocator);
+
+ PARCBuffer *digest = parcBuffer_Allocate(16);
+ for (size_t i = 0; i < parcBuffer_Limit(digest); i++) {
+ parcBuffer_PutUint8(digest, 0);
+ }
+ parcBuffer_Flip(digest);
+ ccnxManifestHashGroup_SetOverallDataDigest(group, digest);
+
+ size_t entrySize = 1;
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+
+ size_t dataSize = 2;
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+
+ size_t blockSize = 3;
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+
+ size_t treeHeight = 4;
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+
+ // Add the hash group to the manifest
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+
+ // Compute the expected size with all of the metadata.
+ // This packet was crafted by hand.
+ size_t expected = 4; // hash group TL
+ expected += 4 + parcBuffer_Remaining(pointer); // pointer TL, pointer V
+ expected += 4; // metadata TL
+ expected += 4 * (4 + 8); // 64-bit integer property TLs, Vs
+ expected += 4 + parcBuffer_Remaining(digest); // digest T and V
+ expected += 4 + strlen("ccnx:/locator"); // name TL, segment TL, and segment V
+
+ // Compute only the size of the metadata
+ size_t metadataSize = expected;
+ metadataSize -= 4; // top-level TL container
+ metadataSize -= (4 + parcBuffer_Remaining(pointer)); // pointer TLV
+ metadataSize -= 4; // metadata TL container
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ // Now do the encoding
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ uint8_t expectedVector[129] = { 0x00, 0x07,
+ 0x00, expected - 4,
+ 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,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer,
+ 0x00, parcBuffer_Remaining(pointer),
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF };
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same HashGroup to be encoded");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ parcBuffer_Release(&digest);
+ ccnxManifestHashGroup_Release(&group);
+ ccnxName_Release(&groupLocator);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c
new file mode 100644
index 00000000..ab339fc1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c
@@ -0,0 +1,320 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_MessageDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+
+#include "testrig_packetwrapper.c"
+
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+// Utility functions to get a field in the format we expect for the testrig.
+// We cannot use the facades because those try to assert a type on the dictionary which
+// is not part of the MessageDecoder.
+
+static CCNxName *
+_getName(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+}
+
+static PARCBuffer *
+_getPayload(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ return ccnxTlvDictionary_GetBuffer(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+}
+
+static int64_t
+_getPayloadType(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+}
+
+static int64_t
+_getExpiryTime(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+}
+
+static int64_t
+_getEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+}
+
+static PARCCryptoHash *
+_getKeyIdRestriction(CCNxTlvDictionary *messageDictionary)
+{
+ return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+}
+
+static PARCCryptoHash *
+_getHashRestriction(CCNxTlvDictionary *messageDictionary)
+{
+ return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, Name);
+ LONGBOW_RUN_TEST_CASE(ContentObject, Payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, PayloadType);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ExpiryTime);
+ LONGBOW_RUN_TEST_CASE(ContentObject, EndChunkNumber);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ v1_content_nameA_keyid1_rsasha256_truthTableEntries,
+ V1_MANIFEST_OBJ_CONTENTOBJECT));
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, Name)
+{
+// TestData *data = longBowTestCase_GetClipBoardData(testCase);
+// testNameGetter(data, V1_MANIFEST_OBJ_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName);
+}
+
+LONGBOW_TEST_CASE(ContentObject, Payload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testBufferGetter(data, V1_MANIFEST_OBJ_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload);
+}
+
+LONGBOW_TEST_CASE(ContentObject, PayloadType)
+{
+ // The payload type is translated from the wire format value to the CCNxPayloadType value,
+ // so this test cannot use the automated framework as the value in the dictionary will not
+ // be the same as the value in the wire format
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool decodeSuccess = ccnxCodecSchemaV1MessageDecoder_Decode(data->decoder, data->dictionary);
+ assertTrue(decodeSuccess, "failure on ccnxCodecSchemaV1MessageDecoder_Decode");
+
+ CCNxPayloadType testPayloadType = (CCNxPayloadType) _getPayloadType(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, V1_MANIFEST_OBJ_PAYLOADTYPE);
+
+ PARCBuffer
+ *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ CCNxPayloadType truthPayloadType = -1;
+ bool success =
+ _translateWirePayloadTypeToCCNxPayloadType((CCNxCodecSchemaV1Types_PayloadType) truthvalue, &truthPayloadType);
+ assertTrue(success, "failure in _translateWirePayloadTypeToCCNxPayloadType for wireFormatValue %"
+ PRId64, truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(truthPayloadType == testPayloadType, "Wrong value, got %d expected %d", testPayloadType,
+ truthPayloadType);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ExpiryTime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testInt64Getter(data, V1_MANIFEST_OBJ_EXPIRY_TIME, ccnxCodecSchemaV1MessageDecoder_Decode, _getExpiryTime);
+}
+
+LONGBOW_TEST_CASE(ContentObject, EndChunkNumber)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testInt64Getter(data, V1_MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV1MessageDecoder_Decode, _getEndChunkNumber);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, Name);
+ LONGBOW_RUN_TEST_CASE(Interest, Payload);
+ LONGBOW_RUN_TEST_CASE(Interest, KeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(Interest, HashRestriction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, Name)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testNameGetter(data, V1_MANIFEST_INT_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName);
+}
+
+LONGBOW_TEST_CASE(Interest, Payload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testBufferGetter(data, V1_MANIFEST_INT_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload);
+}
+
+LONGBOW_TEST_CASE(Interest, KeyIdRestriction)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testHashGetter(data, V1_MANIFEST_INT_KEYID, ccnxCodecSchemaV1MessageDecoder_Decode, _getKeyIdRestriction);
+}
+
+LONGBOW_TEST_CASE(Interest, HashRestriction)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testHashGetter(data, V1_MANIFEST_INT_OBJHASH, ccnxCodecSchemaV1MessageDecoder_Decode, _getHashRestriction);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType)
+{
+ uint32_t sentinel = 0xFFFF;
+
+ struct {
+ CCNxCodecSchemaV1Types_PayloadType wire;
+ CCNxPayloadType payloadType;
+ bool success;
+ } vectors[] = {
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Data, .payloadType = CCNxPayloadType_DATA, .success = true },
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Key, .payloadType = CCNxPayloadType_KEY, .success = true },
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Link, .payloadType = CCNxPayloadType_LINK, .success = true },
+ { .wire = -2, .payloadType = -2, .success = false },
+ { .wire = sentinel, .payloadType = sentinel }
+ };
+
+ for (int i = 0; vectors[i].wire != sentinel; i++) {
+ CCNxPayloadType payloadType = -1;
+ bool success = _translateWirePayloadTypeToCCNxPayloadType(vectors[i].wire, &payloadType);
+ assertTrue(success == vectors[i].success, "Incorrect return index %d, expected %d got %d", i,
+ vectors[i].success, success);
+
+ if (success) {
+ assertTrue(payloadType == vectors[i].payloadType, "Wrong payloadType index %d, expected %d got %d", i,
+ vectors[i].payloadType, payloadType);
+ }
+ }
+}
+
+// =========================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c
new file mode 100644
index 00000000..49452626
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c
@@ -0,0 +1,644 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_MessageEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_Interest.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, Interest);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObjectNameless);
+ LONGBOW_RUN_TEST_CASE(InterestReturn, InterestReturn);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, Interest)
+{
+ // create an Interest that replicates v1_interest_all_fields
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID);
+ TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH);
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD);
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool");
+ uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds;
+ uint32_t hoplimit = CCNxInterestDefault_HopLimit;
+
+ printf("%d %d\n", keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length - 4);
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length);
+ PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, lifetime, keyid, hash, hoplimit);
+
+ ccnxInterest_SetPayloadAndId(interest, payload);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interest);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ interestExtent.offset,
+ interestExtent.offset + interestExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(InterestReturn, InterestReturn)
+{
+ // create an Interest that replicates v1_interest_all_fields
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID);
+ TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH);
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD);
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool");
+ uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds;
+ uint32_t hoplimit = CCNxInterestDefault_HopLimit;
+
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length);
+ PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, lifetime, keyid, hash, hoplimit);
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+
+ ccnxInterest_SetPayloadAndId(interest, payload);
+ parcBuffer_Release(&payload);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_HopLimitExceeded);
+ ccnxTlvDictionary_Release(&interest);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interestReturn);
+
+ size_t packetSize = sizeof(v1_interest_all_fields);
+ uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize);
+ memcpy(testPacket, v1_interest_all_fields, packetSize);
+ testPacket[1] = 0x02; //InterestReturn
+ testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded;
+
+ PARCBuffer *truth = parcBuffer_Wrap(testPacket, packetSize,
+ interestExtent.offset,
+ interestExtent.offset + interestExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ parcSafeMemory_Deallocate((void **) &testPacket);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObjectNameless)
+{
+ // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_PAYLOAD);
+ TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_CONTENTOBJECT);
+
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *contentobject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ NULL, CCNxPayloadType_KEY, payload);
+
+ ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL);
+ ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ ccnxTlvDictionary_Release(&contentobject);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject)
+{
+ // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD);
+ TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_CONTENTOBJECT);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=hello/0xf000=ouch");
+
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *contentobject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_KEY, payload);
+
+ ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL);
+ ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&contentobject);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary);
+
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(InterestReturn)
+{
+ LONGBOW_RUN_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(InterestReturn)
+{
+ size_t packetSize = sizeof(v1_interest_all_fields);
+ uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize);
+ memcpy(testPacket, v1_interest_all_fields, packetSize);
+ testPacket[1] = 0x02; //InterestReturn
+ testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded;
+
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary);
+
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _encodeName);
+ LONGBOW_RUN_TEST_CASE(Local, _encodePayload);
+ LONGBOW_RUN_TEST_CASE(Local, _encodePayloadType);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeEndChunkNumber);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeKeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeContentObjectHashRestriction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <parc/algol/parc_Varint.h>
+
+LONGBOW_TEST_CASE(Local, _encodeName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/0xf001=foot/0xf002=toe/0xf003=nail");
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 23,
+ 0xF0, 0x01, 0x00, 4,
+ 'f', 'o', 'o', 't',
+ 0xF0, 0x02, 0x00, 3,
+ 't', 'o', 'e',
+ 0xF0, 0x03, 0x00, 4,
+ 'n', 'a', 'i', 'l'
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ _encodeName(encoder, dictionary);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodePayload)
+{
+ uint8_t payload[] = { 0xf1, 0xf2, 0xf3 };
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 3,
+ 0xf1, 0xf2, 0xf3
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(payload, sizeof(payload), 0, sizeof(payload));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, buffer);
+
+ _encodePayload(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodePayloadType)
+{
+ CCNxPayloadType type = CCNxPayloadType_LINK;
+
+ uint8_t encoded[] = {
+ 0x00, 0x05, 0x00, 1,
+ CCNxCodecSchemaV1Types_PayloadType_Link
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, type);
+
+ _encodePayloadType(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeExpiryTime)
+{
+ uint64_t expiry = 0x123456789ABCDEF0ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 8,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC, 0xDE, 0xF0
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiry);
+
+ _encodeExpiryTime(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeEndChunkNumber)
+{
+ uint64_t endChunkNumber = 0x818283ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x19, 0x00, 3,
+ 0x81, 0x82, 0x83
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber);
+
+ _encodeEndChunkNumber(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeKeyIdRestriction)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x02, 0x00, 0x24,
+ 0x00, 0x01, 0x00, 0x20,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash);
+
+ _encodeKeyIdRestriction(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+ parcCryptoHash_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeContentObjectHashRestriction)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x03, 0x00, 0x24,
+ 0x00, 0x01, 0x00, 0x20,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION, hash);
+
+ _encodeContentObjectHashRestriction(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+ parcCryptoHash_Release(&hash);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, Unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(UnknownType, Unknown)
+{
+ CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1MessageEncoder_Encode(encoder, unknown);
+ assertTrue(length < 0, "Did not get error return when encoding unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "encoder did not set the error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&unknown);
+}
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c
new file mode 100755
index 00000000..8a33a0e2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c
@@ -0,0 +1,139 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_NameCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ CCNxName *truth = ccnxName_Append(ccnxName_Create(), segment);
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buffer);
+
+ uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0x1020);
+
+ assertTrue(ccnxName_Equals(truth, test), "Name segments do not match");
+
+ ccnxName_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+ ccnxName_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType)
+{
+ uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0xFFFF);
+
+ assertNull(test, "Name should have returned NULL because the name type does not match");
+ assertTrue(ccnxCodecTlvDecoder_Position(decoder) == 0, "Position should not have moved, expected 0, got %zu", ccnxCodecTlvDecoder_Position(decoder));
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Encode)
+{
+ uint8_t truthBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+
+ CCNxName *name = ccnxName_Append(ccnxName_Create(), segment);
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecSchemaV1NameCodec_Encode(encoder, 0x1020, name);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers do not match\n");
+ printf("Excpected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match");
+ }
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c
new file mode 100755
index 00000000..77800055
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c
@@ -0,0 +1,149 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_NameSegmentCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *truth = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ parcBuffer_Release(&buffer);
+
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertTrue(ccnxNameSegment_Equals(truth, test), "Name segments do not match");
+
+ ccnxNameSegment_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+ ccnxNameSegment_Release(&truth);
+}
+
+/**
+ * In this case, there are not enough bytes in the buffer to decode the T and L
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort)
+{
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertNull(test, "Name segments should have been null because there are not enough bytes in buffer");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+/**
+ * In this case, we decode the T and L, but there are not enough bytes for the V
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort)
+{
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00 };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertNull(test, "Name segments should have been null because there are not enough bytes in buffer");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode)
+{
+ uint8_t truthBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match");
+
+ parcBuffer_Release(&test);
+ ccnxNameSegment_Release(&segment);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c
new file mode 100644
index 00000000..abe47608
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c
@@ -0,0 +1,321 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_OptionalHeadersDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ PARCBuffer *optionalHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ PARCBuffer *interestLifetime;
+ PARCBuffer *cacheTime;
+ PARCBuffer *interestFrag;
+ PARCBuffer *objectFrag;
+ PARCBuffer *customHeader;
+
+ // the key for the customHeader
+ uint16_t customHeaderType;
+} TestData;
+
+/**
+ * A packet with all the defined optional headers plus one custom header
+ * This is not actually a packet one would see in real life as it has
+ * headers from both an Interest and a Content Object
+ */
+static uint8_t packet_with_headers[] = {
+ 0x01, 0x01, 0x00, 120, // ver = 1, type = interest, length = 120
+ 0x01, 0x00, 0x00, 88, // hopLimit = 1, reserved = 0, header length = 88
+ // ------------------------
+ // byte 8
+ 0x00, 0x01, 0x00, 0x08, // Interest Lifetime (type 1)
+ 0x20, 0x30, 0x40, 0x50, // 0x2030405060708090
+ 0x60, 0x70, 0x80, 0x90,
+ // ------------------------
+ // byte 20
+ 0x00, 0x02, 0x00, 0x08, // Recommended Cache Time (type 2)
+ 0x21, 0x31, 0x41, 0x51, // 0x2030405060708090
+ 0x61, 0x71, 0x81, 0x91,
+ // ------------------------
+ // byte 32
+ 0x00, 0x03, 0x00, 0x0C, // Interest Fragment (type 3)
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0
+ // ------------------------
+ // byte 48
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment (type 4)
+ 0xC1, 0xC2, 0xC3, 0xC4,
+ 0xC5, 0xC6, 0xC7, 0xC8, // fragment 0xC1C2C3C4C5C6C7C8
+ 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0
+ 0xD1, 0xD2, 0xD3, 0xD4,
+ 0xD5, 0xD6, 0xD7, 0xD8, // fragment 0xD1D2D3D4D5D6D7D8
+ // ------------------------
+ // byte 72
+ 0x01, 0x00, 0x00, 12, // Custom header (type 256), length 12
+ 0xA0, 0xA1, 0xA2, 0xA3,
+ 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB,
+ // ------------------------
+ // byte 88
+ 0x00, 0x01, 0x00, 29, // type = interest, length = 29
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x10, // type = name, length = 16
+ 0x00, 0x02, 0x00, 0x04, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x04, // type = keyid, length = 4
+ 0xA0, 0xB0, 0xC0, 0xD0, // 0xA0B0C0D0
+ // ------------------------
+ // byte 120
+};
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ // setup the decoder and decode the optional headers
+ data->optionalHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 8, 88);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->optionalHeader);
+ data->dictionary = ccnxTlvDictionary_Create(10, 5);
+
+ // setup the truth values
+ data->interestLifetime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 12, 20);
+ data->cacheTime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 24, 32);
+
+ data->interestFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 36, 48);
+ data->objectFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 52, 72);
+
+ data->customHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 76, 88);
+ data->customHeaderType = 0x0100;
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->optionalHeader);
+
+ parcBuffer_Release(&data->interestLifetime);
+ parcBuffer_Release(&data->cacheTime);
+ parcBuffer_Release(&data->interestFrag);
+ parcBuffer_Release(&data->objectFrag);
+ parcBuffer_Release(&data->customHeader);
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * One of the TLVs will extend beyond the end of the buffer. Should fail.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Make one of the fields 255 bytes
+ uint8_t original = packet_with_headers[10];
+ packet_with_headers[10] = 0xFF;
+ bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+
+ // now set it back
+ packet_with_headers[10] = original;
+
+ assertFalse(success, "Should have failed to parse when a TLV exceeds bounary");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary);
+ assertTrue(parcBuffer_Equals(test, data->objectFrag), "Wrong value")
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->objectFrag, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary);
+ assertTrue(parcBuffer_Equals(test, data->interestFrag), "Wrong value")
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->interestFrag, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ uint64_t lifetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(data->dictionary);
+
+ uint64_t trueLifetime = 0;
+ ccnxCodecTlvUtilities_GetVarInt(data->interestLifetime, parcBuffer_Remaining(data->interestLifetime), &trueLifetime);
+
+ assertTrue(trueLifetime == lifetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueLifetime, lifetime);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ uint64_t cachetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(data->dictionary);
+
+ uint64_t trueCachetime = 0;
+ ccnxCodecTlvUtilities_GetVarInt(data->cacheTime, parcBuffer_Remaining(data->cacheTime), &trueCachetime);
+
+ assertTrue(trueCachetime == cachetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueCachetime, cachetime);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType);
+ assertTrue(parcBuffer_Equals(test, data->customHeader), "Wrong value for header type %02X", data->customHeaderType)
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->customHeader, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+// ========
+// test for missing values
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ assertFalse(exists, "Dictionary reports it has a missing field");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ assertFalse(exists, "Dictionary reports it has a missing field");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_OptionalHeadersDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c
new file mode 100644
index 00000000..1950eef2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c
@@ -0,0 +1,205 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_OptionalHeadersEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h>
+
+#include "testrig_encoder.c"
+
+static TruthTableEntry
+TRUTHTABLENAME(interest_optional_headers)[] =
+{
+ { .wellKnownType = false, .indexOrKey = V1_MANIFEST_INT_OPTHEAD, .bodyManifest = true, .extent = { 8, 28 } }, // index = 0
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, // index = 1
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } }, // index = 2
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+static TruthTableEntry
+TRUTHTABLENAME(contentobject_optional_headers)[] =
+{
+ { .wellKnownType = false, .indexOrKey = V1_MANIFEST_OBJ_OPTHEAD, .bodyManifest = true, .extent = { 8, 36 } }, // 0
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_nameA,
+ sizeof(v1_interest_nameA),
+ TRUTHTABLENAME(interest_optional_headers),
+ V1_MANIFEST_INT_OPTHEAD));
+
+ // commonSetup will not add headers...
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset + TRUTHTABLENAME(interest_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset + TRUTHTABLENAME(interest_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary);
+ assertTrue(length >= 0, "Error on Encode: length %zd", length);
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_content_nameA_crc32c,
+ sizeof(v1_content_nameA_crc32c),
+ TRUTHTABLENAME(contentobject_optional_headers),
+ V1_MANIFEST_OBJ_OPTHEAD));
+
+ // commonSetup will not add headers...
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary);
+ assertTrue(length >= 0, "Error on Encode: length %zd", length);
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, Unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(UnknownType, Unknown)
+{
+ CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(encoder, unknown);
+ assertTrue(length < 0, "Did not get error return when encoding unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "encoder did not set the error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&unknown);
+}
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_OptionalHeadersEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c
new file mode 100755
index 00000000..42d5be41
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c
@@ -0,0 +1,684 @@
+/*
+ * 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.
+ */
+
+/**
+ * Decode whole packets then spot-check that fields from each section appear. We don't need
+ * to exhastively test here, as the individual decoders are exhaustively tested.
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_PacketDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h>
+
+#include "testrig_packetwrapper.c"
+
+#include <ccnx/common/internal/ccnx_ContentObjectFacadeV1.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Control);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_zero_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_no_payload);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ 0,
+ sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ CCNxName *trueName = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI);
+
+ assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal")
+ {
+ printf("Expected\n");
+ ccnxName_Display(trueName, 3);
+ printf("Got\n");
+ ccnxName_Display(name, 3);
+ }
+
+ ccnxName_Release(&trueName);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t expiryTime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+
+ TlvExtent expiryExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_EXPIRY_TIME);
+
+ parcBuffer_SetPosition(packetBuffer, expiryExtent.offset);
+ uint64_t trueTime;
+ ccnxCodecTlvUtilities_GetVarInt(packetBuffer, expiryExtent.length, &trueTime);
+
+ assertTrue(expiryTime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, expiryTime);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID);
+ PARCBuffer *trueKeyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), keyidExtent.offset, keyidExtent.offset + keyidExtent.length);
+
+ assertTrue(parcBuffer_Equals(keyid, trueKeyid), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueKeyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(keyid, 3);
+ }
+
+ parcBuffer_Release(&trueKeyid);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_zero_payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_zero_payload, sizeof(v1_content_zero_payload), 0, sizeof(v1_content_zero_payload));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *testName = CCNxContentObjectFacadeV1_Implementation.getName(dictionary);
+ assertNotNull(testName, "Got null name on decode");
+
+ PARCBuffer *testPayload = CCNxContentObjectFacadeV1_Implementation.getPayload(dictionary);
+ assertNotNull(testPayload, "got null payload")
+ assertTrue(parcBuffer_Remaining(testPayload) == 0, "Wrong length, expected 0 got %zu", parcBuffer_Remaining(testPayload));
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_no_payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_no_payload, sizeof(v1_content_no_payload), 0, sizeof(v1_content_no_payload));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *test = CCNxContentObjectFacadeV1_Implementation.getName(dictionary);
+ assertNotNull(test, "Got null name on decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Control)
+{
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Control)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Control)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_cpi_add_route_crc32c, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent validationPayloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS);
+ PARCBuffer *trueValidationPayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), validationPayloadExtent.offset, validationPayloadExtent.offset + validationPayloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(test, trueValidationPayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueValidationPayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&trueValidationPayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxValidationFacadeV1_GetCryptoSuite(dictionary);
+ PARCCryptoSuite trueCryptoSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ assertTrue(test == trueCryptoSuite, "Wrong crypto suite, expected %d got %d", trueCryptoSuite, test);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, interest_bad_message_length);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Lifetime);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Name);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_bad_validation_alg);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_validation_alg_overrun);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, interest_bad_message_length)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_interest_all_fields, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_Lifetime)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+
+ TlvExtent lifetimeExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_LIFETIME);
+
+ parcBuffer_SetPosition(packetBuffer, lifetimeExtent.offset);
+ uint64_t trueTime;
+ ccnxCodecTlvUtilities_GetVarInt(packetBuffer, lifetimeExtent.length, &trueTime);
+
+ assertTrue(lifetime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, lifetime);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_Name)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ CCNxName *trueName = ccnxName_CreateFromCString(v1_interest_all_fields_URI);
+
+ assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal")
+ {
+ printf("Expected\n");
+ ccnxName_Display(trueName, 3);
+ printf("Got\n");
+ ccnxName_Display(name, 3);
+ }
+
+ ccnxName_Release(&trueName);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+/*
+ * This packet does not have a validation section, so the test is that its missing
+ */
+LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ assertNull(keyid, "Got a non-null keyid from a packet without one");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+/*
+ * Packet does not have validation, test for missing
+ */
+LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ assertNull(payload, "Got a non-null validation payload from a packet without one");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite suite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ PARCCryptoSuite trueSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ assertTrue(suite == trueSuite, "Wrong crypto suite, expected %d got %d", trueSuite, suite);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, dictionary);
+ assertTrue(success, "Error on decode");
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_bad_validation_alg)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_validation_alg, sizeof(v1_interest_bad_validation_alg), 0, sizeof(v1_interest_bad_validation_alg));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_validation_alg_overrun)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_validation_alg_overrun, sizeof(v1_interest_validation_alg_overrun), 0, sizeof(v1_interest_validation_alg_overrun));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+// =========================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c
new file mode 100755
index 00000000..eb79502e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c
@@ -0,0 +1,1054 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_PacketEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(InterestReturn);
+ LONGBOW_RUN_TEST_FIXTURE(Control);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256);
+ LONGBOW_RUN_TEST_CASE(ContentObject, zero_length_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, null_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, no_cryptosuite);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make a dictionary equivalent to v1_content_nameA_keyid1_rsasha256 and encode it then compare
+ */
+LONGBOW_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI);
+
+ TlvExtent payloadExtent =
+ getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ payloadExtent.offset,
+ payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_KEY, payload);
+
+ TlvExtent fragmentExtent =
+ getTruthTableHeaderExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ fragmentExtent.offset,
+ fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG, fragment);
+
+ uint64_t expiryTime = 1388534400000ULL;
+ ccnxContentObject_SetExpiryTime(message, expiryTime);
+
+ uint64_t endChunkNumber = 0x06050403;
+ ccnxContentObject_SetFinalChunkNumber(message, endChunkNumber);
+
+ TlvExtent keyIdExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID);
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ keyIdExtent.offset,
+ keyIdExtent.offset + keyIdExtent.length);
+
+ TlvExtent keyExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PUBKEY);
+ PARCBuffer *key = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ keyExtent.offset,
+ keyExtent.offset + keyExtent.length);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_RSA_SHA256);
+ ccnxValidationFacadeV1_SetKeyId(message, keyid);
+ ccnxValidationFacadeV1_SetPublicKey(message, key);
+
+ TlvExtent sigExtent =
+ getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ sigExtent.offset,
+ sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s",
+ ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(v1_content_nameA_keyid1_rsasha256),
+ "Wrong length, expected %zu got %zd", sizeof(v1_content_nameA_keyid1_rsasha256), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ 0,
+ sizeof(v1_content_nameA_keyid1_rsasha256));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+
+LONGBOW_TEST_CASE(ContentObject, zero_length_payload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+ PARCBuffer *payload = parcBuffer_Allocate(0);
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, payload);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ parcBuffer_Display(encoded, 3);
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(ContentObject, null_payload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, NULL);
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+/*
+ * A content object without a cryptosuite should not be signed
+ */
+LONGBOW_TEST_CASE(ContentObject, no_cryptosuite)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, NULL);
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ // it should be 33 bytes without a signature
+ assertTrue(parcBuffer_Remaining(encoded) == 33, "Wrong length exepcted 33 got %zu", parcBuffer_Remaining(encoded));
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c);
+ LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make an interest equivalent to v1_interest_nameA_crc32c and encode it
+ */
+LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+/*
+ * Make an interest equivalent to v1_interest_nameA_crc32c and encode it
+ */
+LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(message, NULL);
+ assertNotNull(iovec, "Got null iovec from ccnxCodecSchemaV1PacketEncoder_DictionaryEncode");
+
+ size_t length = ccnxCodecNetworkBufferIoVec_Length(iovec);
+ assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ int iovecCount = ccnxCodecNetworkBufferIoVec_GetCount(iovec);
+ PARCBuffer *test = parcBuffer_Allocate(length);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+ for (int i = 0; i < iovecCount; i++) {
+ parcBuffer_PutArray(test, array[i].iov_len, array[i].iov_base);
+ }
+ parcBuffer_Flip(test);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(InterestReturn)
+{
+ LONGBOW_RUN_TEST_CASE(InterestReturn, v1_interest_return);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(InterestReturn)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make an interest return and encode it
+ */
+LONGBOW_TEST_CASE(InterestReturn, v1_interest_return)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxInterest *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+ ccnxName_Release(&name);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(interest, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+ parcBuffer_Release(&fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(interest, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(interest, sig);
+ parcBuffer_Release(&sig);
+
+ CCNxTlvDictionary *message =
+ ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoResources);
+ ccnxInterest_Release(&interest);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ ssize_t expectedLength = sizeof(v1_interest_nameA_crc32c);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == expectedLength, "Wrong length, expected %zu got %zd", expectedLength, length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c_returned, sizeof(v1_interest_nameA_crc32c_returned), 0, sizeof(v1_interest_nameA_crc32c_returned));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]);
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Control)
+{
+ LONGBOW_RUN_TEST_CASE(Control, payload);
+ LONGBOW_RUN_TEST_CASE(Control, cryptosuite);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Control)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Control)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Control, payload)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xa4, 0x00, 0x22,
+ 0x00, 0x00, 0x00, 0x08,
+
+ 0xbe, 0xef, 0x00, 0x16, // control message
+
+ 0x7b, 0x22, 0x74, 0x68, // {"th
+ 0x69, 0x73, 0x20, 0x69, // is i
+ 0x73, 0x22, 0x3a, 0x22, // s":"
+ 0x61, 0x6e, 0x6e, 0x6f, // anno
+ 0x79, 0x69, 0x6e, 0x67, // ying
+ 0x22, 0x7d // "}
+ };
+
+
+ CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddString(json, "this is", "annoying");
+
+ ccnxTlvDictionary_PutJson(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json);
+ parcJSON_Release(&json);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ // verify
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Control, cryptosuite)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xA4, 0x00, 16,
+ 0x00, 0x00, 0x00, 8,
+ 0xBE, 0xEF, 0x00, 4,
+ 'a', 'b', 'c', 'd',
+ 0x00, 0x03, 0x00, 4,
+ 0x00, 0x02, 0x00, 0
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *payload = parcBuffer_Wrap(encoded, sizeof(encoded), 12, 16);
+
+ CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+ ccnxValidationCRC32C_Set(message);
+
+ ccnxValidationCRC32C_Set(message);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(test, "Got null buffer from encoder");
+ uint8_t testSuite = parcBuffer_GetAtIndex(test, 21);
+ assertTrue(testSuite == 2, "Wrong cryptosuite, expected 2 got %u", testSuite);
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&truth);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * try to encode a message with unknown message type
+ */
+LONGBOW_TEST_CASE(UnknownType, unknown)
+{
+ // this initializes the dictionary to unknown type
+ CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertTrue(length < 0, "Did not get error condition for unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "Did not get an error for invalid encoding");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Missing);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_Interest);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeOptionalHeaders);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Interest);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeCPI);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Unknown);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Missing);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Missing);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _getHopLimit_Present)
+{
+ uint8_t hoplimit = 77;
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hoplimit);
+
+ uint8_t test = _getHopLimit(dict);
+ assertTrue(test == hoplimit, "Got wrong hoplimit, expected %u got %u", hoplimit, test);
+ ccnxTlvDictionary_Release(&dict);
+}
+
+LONGBOW_TEST_CASE(Local, _getHopLimit_Missing)
+{
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ uint8_t test = _getHopLimit(dict);
+ assertTrue(test == CCNxInterestDefault_HopLimit, "Got wrong hoplimit, expected %u got %u", CCNxInterestDefault_HopLimit, test);
+ ccnxTlvDictionary_Release(&dict);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeFixedHeader_ContentObject)
+{
+ uint8_t encoded[] = {
+ 0x01, 0x01, 0x00, 100, // ver = 1, type = content object, length = 100
+ 0x00, 0x00, 0x00, 14, // reserved = 0x0000000, header length = 14
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_ContentObject, 14, 100);
+ assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeFixedHeader_Interest)
+{
+ uint8_t encoded[] = {
+ 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100
+ 0x1f, 0x00, 0x00, 14, // hoplimit = 31, reserved = 0x0000, header length = 14
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, 31);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_Interest, 14, 100);
+ assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeOptionalHeaders)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, 0xEAEB);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeOptionalHeaders(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeMessage_Interest)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 13,
+ 0x00, 0x00, 0x00, 9,
+ 0x00, CCNxNameLabelType_NAME, 0x00, 5,
+ 'p', 'o', 'p', 'p', 'y'
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/poppy");
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+ assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_Interest, "Wrong packet type, expected %d got %d",
+ CCNxCodecSchemaV1Types_PacketType_Interest, packetType);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeMessage_ContentObject)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x02, 0x00, 13,
+ 0x00, 0x00, 0x00, 9,
+ 0x00, CCNxNameLabelType_NAME, 0x00, 5,
+ 'p', 'o', 'p', 'p', 'y'
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/poppy");
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+ assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_ContentObject, "Wrong packet type, expected %d got %d",
+ CCNxCodecSchemaV1Types_PacketType_ContentObject, packetType);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeCPI)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x02, 0x03, 0x99, //
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, truth);
+
+ ssize_t length = _encodeCPI(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * This test requires that we set the message type to some unknown value, which we get if
+ * we create a dictionary with ccnxTlvDictionary_Create() and dont call anything to set
+ * the message type. It will be "CCNxTlvDictionary_Unknown".
+ */
+LONGBOW_TEST_CASE(Local, _encodeMessage_Unknown)
+{
+ CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(20, 20);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length < 0, "wrong length, expected negative got %zd", length);
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "Got null error when an error condition should have been set");
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Present)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload);
+
+ ssize_t length = _encodeValidationAlg(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ssize_t length = _encodeValidationAlg(encoder, dict);
+ assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length);
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Present)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x04, 0x00, 4, // validation payload, length = 4
+ 0x00, 0x02, 0x03, 0x99, //
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload);
+
+ ssize_t length = _encodeValidationPayload(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ssize_t length = _encodeValidationPayload(encoder, dict);
+ assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length);
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c
new file mode 100755
index 00000000..ccaa8b13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c
@@ -0,0 +1,118 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_TlvDictionary.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_TlvDictionary)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_TlvDictionary)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_TlvDictionary)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest");
+ assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateContentObject");
+ assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary is not a content object");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateControl");
+ assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary is not a control");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_TlvDictionary);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c
new file mode 100755
index 00000000..82cf69d1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c
@@ -0,0 +1,450 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ValidationDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+
+#include "testrig_packetwrapper.c"
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(DecodeAlg);
+ LONGBOW_RUN_TEST_FIXTURE(DecodePayload);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(DecodeAlg)
+{
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, CRC32C);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, HMAC_SHA256);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, RSA_SHA256);
+
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, Cert);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, PublicKey);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyId);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, SigTime);
+
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName_Invalid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DecodeAlg)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DecodeAlg)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, CRC32C)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, HMAC_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_HMAC_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, RSA_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_RSA_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, Cert)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x0C, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, PublicKey)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x0B, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyId)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x09, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyName)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 44,
+ 0x00, 0x0E, 0x00, 40,
+ // --- name
+ 0x00, 0x00, 0x00, 16,
+ 0x00, 0x03, 0x00, 5,
+ 'a', 'p', 'p', 'l',
+ 'e',
+ 0x00, 0x03, 0x00, 3,
+ 'p', 'i', 'e',
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie");
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 32, 36);
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 40, 48);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ // now test the 3 decoded fields
+ CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ assertTrue(ccnxName_Equals(testName, name), "keynames do not match")
+ {
+ printf("Expected\n");
+ ccnxName_Display(name, 3);
+ printf("Got\n");
+ ccnxName_Display(testName, 3);
+ }
+
+ PARCBuffer *testKeyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ assertTrue(parcBuffer_Equals(testKeyid, keyid), "keyid do not match")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(testKeyid, 3);
+ }
+
+ PARCBuffer *testHash = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+ assertTrue(parcBuffer_Equals(testHash, hash), "keyid do not match")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(hash, 3);
+ printf("Got\n");
+ parcBuffer_Display(testHash, 3);
+ }
+
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&hash);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyName_Invalid)
+{
+ // link is missing the Name
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 24,
+ 0x00, 0x0E, 0x00, 20,
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertFalse(success, "Should have failed decode as keyname is invalid");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, SigTime)
+{
+ uint64_t sigtime = 0x1122334455667788ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 12,
+ 0x00, 0x0F, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ assertTrue(test == sigtime, "Wrong sig time, expected %" PRIx64 ", got %" PRIx64, sigtime, test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(DecodePayload)
+{
+ LONGBOW_RUN_TEST_CASE(DecodePayload, payload);
+ LONGBOW_RUN_TEST_CASE(DecodePayload, payload_zero);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DecodePayload)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DecodePayload)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(DecodePayload, payload)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x04, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ // the caller has already parsed the T and L, so we point to just payload
+ ccnxCodecTlvDecoder_Advance(decoder, 4);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary);
+ assertTrue(success, "Failed to decode a valid payload: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 4, 12);
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodePayload, payload_zero)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x04, 0x00, 0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ // the caller has already parsed the T and L, so we point to just payload
+ ccnxCodecTlvDecoder_Advance(decoder, 4);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary);
+ assertFalse(success, "Should have failed on 0-length payload");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+// =========================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c
new file mode 100755
index 00000000..8a4d951a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c
@@ -0,0 +1,565 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ValidationEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+
+#include "testrig_packetwrapper.c"
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(EncodeAlg);
+ LONGBOW_RUN_TEST_FIXTURE(EncodePayload);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(EncodeAlg)
+{
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, CRC32C);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, HMAC_SHA256);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, RSA_SHA256);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, DeduceFromSigner);
+
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeCertificate);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodePublicKey);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyId);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyName);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EncodeAlg)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EncodeAlg)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, CRC32C)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ PARCCryptoSuite suite = PARCCryptoSuite_NULL_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, HMAC_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ PARCCryptoSuite suite = PARCCryptoSuite_HMAC_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, RSA_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, DeduceFromSigner)
+{
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvsuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvsuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+ parcSigner_Release(&signer);
+}
+
+// =======
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeCertificate)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0C, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *cert = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetCertificate(dictionary, cert);
+
+ ssize_t length = _encodeCertificate(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&cert);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodePublicKey)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0B, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *key = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetPublicKey(dictionary, key);
+
+ ssize_t length = _encodePublicKey(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&key);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyId)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x09, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetKeyId(dictionary, keyid);
+
+ ssize_t length = _encodeKeyId(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&keyid);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyName)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0E, 0x00, 40,
+ // --- name
+ 0x00, 0x00, 0x00, 16,
+ 0x00, 0x03, 0x00, 5,
+ 'a', 'p', 'p', 'l',
+ 'e',
+ 0x00, 0x03, 0x00, 3,
+ 'p', 'i', 'e',
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 32);
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 36, 44);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie");
+ CCNxLink *link = ccnxLink_Create(name, keyid, hash);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetKeyName(dictionary, link);
+
+ ssize_t length = _encodeKeyName(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&hash);
+ ccnxName_Release(&name);
+ ccnxLink_Release(&link);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified)
+{
+ uint64_t sigtime = 0x1122334455667788ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x0F, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetSigningTime(dictionary, sigtime);
+
+ ssize_t length = _encodeSignatureTime(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Do not specify a signing time, but rather set a Signer and let the code
+ * create the time on its own
+ */
+LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ PARCBuffer *password = parcBuffer_Wrap("password", 8, 0, 8);
+ PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(password);
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ ssize_t length = _encodeSignatureTime(encoder, dictionary);
+ assertTrue(length == 12, "Wrong length, expected 12, got %zd", length);
+
+ parcBuffer_Release(&password);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(EncodePayload)
+{
+ LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Specified);
+ LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Generated);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EncodePayload)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EncodePayload)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(EncodePayload, payload_Specified)
+{
+ uint8_t encoded[] = {
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetPayload(dictionary, truth);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Put the guts of v1_interest_nameA_crc32c in to the encoding buffer and mark it
+ * as the signature block. Generate the CRC and make sure we got the right thing.
+ */
+LONGBOW_TEST_CASE(EncodePayload, payload_Generated)
+{
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_INTEREST);
+
+ // This will test against the string (Interest, ValidationAlg, ValidationPayload)
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c,
+ sizeof(v1_interest_nameA_crc32c),
+ interestExtent.offset,
+ sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ // This will append from the beginning of the Interest message up to the end of the ValidationAlg
+ // This space is all marked as the "to-be-signed" section.
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ size_t signedInfoLenth = sizeof(v1_interest_nameA_crc32c) - 8 - interestExtent.offset;
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, signedInfoLenth, v1_interest_nameA_crc32c + interestExtent.offset);
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+
+ // add the validation payload container, then generate the signature
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 4);
+
+ // Do the actual encoding. This will calculate the signature on the fly.
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary);
+ assertTrue(length == 4, "Wrong length, expected 4 got %zd", length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ // Tests that we got the right signature (CRC32c in this case)
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+}
+
+// =========================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
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);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c
new file mode 100644
index 00000000..9a213b13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c
@@ -0,0 +1,516 @@
+/*
+ * 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.
+ */
+
+/**
+ * This test rig sets up test data to wrap a packet and prepare it for use in a decoder
+ *
+ * A hand-encoded packet, such as from the testdata directory can be passed to commonSetup and then
+ * run automated tests against it based on its manifest.
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 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,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType);
+ * }
+ *
+ * @endcode
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h>
+
+/**
+ * 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 {
+ PARCBuffer *interest;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ uint8_t *packet;
+ size_t packetLength;
+ TruthTableEntry *truthTable;
+} TestData;
+
+/**
+ * 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, position 0, 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->interest = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->interest);
+
+ // content objects have more fields than interests, so use that
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+ return data;
+}
+
+void
+commonSetupWholePacket(LongBowTestCase *testCase, uint8_t *packet, size_t length, TruthTableEntry *truthTable)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->interest = parcBuffer_Wrap(packet, length, 0, length);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->interest);
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+}
+
+void
+commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->interest);
+ parcMemory_Deallocate((void **) &data);
+}
+
+/**
+ * Tests that an int32_t getter returns the right value
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 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,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType);
+ * }
+ * * @endcode
+ */
+void
+testInt32Getter(LongBowTestCase *testCase, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ int32_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ containerDecoder(data->decoder, data->dictionary);
+ int32_t testvalue = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(testvalue == (int32_t) truthvalue, "Wrong value, got %d expected %d", testvalue, (int32_t) truthvalue);
+}
+
+/**
+ * Tests that an int64_t getter returns the right value
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 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,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_PROTOINFO, .bodyManifest=true, .extent = { 76, 26} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_ENDSEGMENT, .bodyManifest=true, .extent = {101, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_PROTOINFO);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt64Getter(testCase, MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV0ProtoInfo_Decode, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber);
+ * }
+ *
+ * @endcode
+ */
+void
+testInt64Getter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ int64_t (*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ int64_t testvalue = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(testvalue == (int64_t) truthvalue, "Wrong value, got %" PRId64 " expected %" PRId64, testvalue, (int64_t) truthvalue);
+}
+
+/**
+ * Tests that a buffer getter returns the right buffer
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset = 117
+ * 0x00, 0x05, 0x00, 0x06, // signature block, length = 6
+ * 0x00, 0x0E, 0x00, 0x02, // signature bits, length = 2
+ * 0xBE, 0xEF // value = 0xBEEF
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBLOCK, .bodyManifest=true, .extent = {117, 6} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBITS, .bodyManifest=true, .extent = {121, 2} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_SIGBLOCK);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0SigBlock_GetSignatureBits)
+ * {
+ * testBufferGetter(testCase, MANIFEST_OBJ_SIGBITS, ccnxCodecSchemaV0SigBlock_Decode, ccnxCodecSchemaV0SigBlock_GetSignatureBits);
+ * }
+ *
+ * @endcode
+ */
+void
+testBufferGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ PARCBuffer *(*getter)(const CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ PARCBuffer *test = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truth = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+}
+
+void
+testHashGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ PARCCryptoHash *(*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ PARCCryptoHash *testHash = getter(data->dictionary);
+
+ // look up the true hash buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthBuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+
+ // decode the hash value
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer);
+ PARCCryptoHash *truthHash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, extent.length);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+
+ // compare the decoded value against the expected value
+ assertTrue(parcCryptoHash_Equals(testHash, truthHash), "Hashes not equal")
+ {
+ printf("Expected:\n");
+ printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(truthHash)));
+ printf("Got:\n");
+ printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(testHash)));
+ }
+
+ parcCryptoHash_Release(&truthHash);
+ parcBuffer_Release(&truthBuffer);
+}
+
+void
+testNameGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ CCNxName *(*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ CCNxName *test = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+
+ // we need to backup 4 bytes to get the TLV container
+ PARCBuffer *truthBuffer =
+ parcBuffer_Wrap(data->packet, data->packetLength, extent.offset - 4, extent.offset + extent.length);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer);
+ CCNxName *truthName = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+
+ assertTrue(ccnxName_Equals(test, truthName), "Names not equal")
+ {
+ printf("Expected:\n");
+ ccnxName_Display(truthName, 3);
+ printf("Got:\n");
+ ccnxName_Display(test, 3);
+ }
+
+ ccnxName_Release(&truthName);
+ parcBuffer_Release(&truthBuffer);
+}
+
+void
+testMissingInt32Getter(LongBowTestCase *testCase, int32_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int32_t test = getter(data->dictionary);
+
+ assertTrue(test == -1, "Wrong value, got %d expected %d", test, -1);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingInt64Getter(LongBowTestCase *testCase, int64_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int64_t test = getter(data->dictionary);
+
+ assertTrue(test == -1, "Wrong value, got %" PRId64 " expected %d", test, -1);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingNameGetter(LongBowTestCase *testCase, CCNxName *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingBufferGetter(LongBowTestCase *testCase, PARCBuffer *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingDictionaryGetter(LongBowTestCase *testCase, CCNxTlvDictionary *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt
new file mode 100644
index 00000000..c5c70ce4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnxCodecSchemaV1_CryptoSuite
+ test_ccnxCodecSchemaV1_FixedHeaderDecoder
+ test_ccnxCodecSchemaV1_FixedHeaderEncoder
+ test_ccnxCodecSchemaV1_LinkCodec
+ test_ccnxCodecSchemaV1_MessageDecoder
+ test_ccnxCodecSchemaV1_MessageEncoder
+ test_ccnxCodecSchemaV1_NameCodec
+ test_ccnxCodecSchemaV1_NameSegmentCodec
+ test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+ test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+ test_ccnxCodecSchemaV1_PacketDecoder
+ test_ccnxCodecSchemaV1_PacketEncoder
+ test_ccnxCodecSchemaV1_TlvDictionary
+ test_ccnxCodecSchemaV1_ValidationDecoder
+ test_ccnxCodecSchemaV1_ValidationEncoder
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h
new file mode 100644
index 00000000..70899d13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * Defines the truthtable manifest constants used by the version 1 test vectors.
+ *
+ */
+
+/**
+ * Schema for Control Plane Interface packets. These packets are a TLV wrapping
+ * the control JSON.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#ifndef Libccnx_v1_CPISchema_h
+#define Libccnx_v1_CPISchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+// -----------------------------------------------------
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ V1_MANIFEST_CPI_PAYLOAD = 0,
+ V1_MANIFEST_CPI_SIGBITS = 5, // the payload of the signature
+ V1_MANIFEST_CPI_ValidationAlg = 6, // start of validation algorithm
+ V1_MANIFEST_CPI_ValidationPayload = 7, // start of validation payload
+ V1_MANIFEST_CPI_BODYEND = 8
+} V1_ManifestCPIBody;
+
+typedef enum {
+ V1_MANIFEST_CPI_HEADEND = 0
+} V1_ManifestCPIHeaders;
+
+#endif // Libccnx_tlv_CPISchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h
new file mode 100644
index 00000000..cb59d937
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is from the version 1 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_v1_ContentObjectSchema_h
+#define Libccnx_v1_ContentObjectSchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+#define T_CONTENTOBJECT 0x0002
+
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ // top level entities
+ V1_MANIFEST_OBJ_NAME = 0,
+ V1_MANIFEST_OBJ_CONTENTOBJECT = 1, // the top container
+ V1_MANIFEST_OBJ_NAMEAUTH = 2,
+ V1_MANIFEST_OBJ_PAYLOADTYPE = 3,
+ V1_MANIFEST_OBJ_PAYLOAD = 4,
+ V1_MANIFEST_OBJ_SIGBITS = 5,
+
+ // inside the name authenticator
+ V1_MANIFEST_OBJ_KEYID = 6,
+ V1_MANIFEST_OBJ_CRYPTO_SUITE = 7,
+ V1_MANIFEST_OBJ_KEY = 8,
+ V1_MANIFEST_OBJ_CERT = 9,
+ V1_MANIFEST_OBJ_KEYNAME = 10,
+ V1_MANIFEST_OBJ_KEYNAME_NAME = 11,
+ V1_MANIFEST_OBJ_KEYNAME_OBJHASH = 12,
+
+ // inside the protocol information
+ V1_MANIFEST_OBJ_METADATA = 13,
+
+ // inside metadata
+ V1_MANIFEST_OBJ_OBJ_TYPE = 14,
+ V1_MANIFEST_OBJ_CREATE_TIME = 15,
+ V1_MANIFEST_OBJ_EXPIRY_TIME = 16,
+
+ // inside signature block
+ V1_MANIFEST_OBJ_ValidationPayload = 17,
+ V1_MANIFEST_OBJ_ENDSEGMENT = 18,
+ V1_MANIFEST_OBJ_PUBKEY = 19,
+
+ V1_MANIFEST_OBJ_ValidationAlg = 20,
+ V1_MANIFEST_OBJ_SigningTime = 21,
+ V1_MANIFEST_OBJ_BODYEND = 22
+} SchemaV1ManifestContentObjectBody;
+
+typedef enum {
+ V1_MANIFEST_OBJ_OPTHEAD = 0,
+ V1_MANIFEST_OBJ_E2EFRAG = 2,
+ V1_MANIFEST_OBJ_FIXEDHEADER = 3,
+ V1_MANIFEST_OBJ_RecommendedCacheTime = 4,
+ V1_MANIFEST_OBJ_HEADEND = 5
+} SchemaV1ManifestContentObjectHeaders;
+
+#endif // Libccnx_tlv_ContentObjectSchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h
new file mode 100644
index 00000000..894b3cc7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is from the version 0 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_v1_InterestSchema_h
+#define Libccnx_v1_InterestSchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+// -----------------------------------------------------
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ V1_MANIFEST_INT_INTEREST = 0, // start of Interest body to end
+
+ V1_MANIFEST_INT_NAME = 1,
+ V1_MANIFEST_INT_KEYID = 2,
+ V1_MANIFEST_INT_OBJHASH = 3,
+ V1_MANIFEST_INT_PAYLOAD = 4,
+ V1_MANIFEST_INT_IPIDM = 5,
+
+ V1_MANIFEST_INT_ValidationAlg = 6, // start of validation algorithm
+ V1_MANIFEST_INT_ValidationPayload = 7, // start of validation payload
+
+ V1_MANIFEST_INT_BODYEND = 7
+} ScheamV1ManifestInterestBody;
+
+typedef enum {
+ V1_MANIFEST_INT_OPTHEAD = 0, // the start of the optional headers
+ V1_MANIFEST_INT_LIFETIME = 1,
+ V1_MANIFEST_INT_E2EFRAG = 2,
+ V1_MANIFEST_INT_HEADEND = 3,
+} ScheamV1ManifestInterestHeaders;
+
+
+#define T_INTEREST 0x0001
+
+#endif // Libccnx_tlv_InterestSchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h
new file mode 100644
index 00000000..e4695849
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h
@@ -0,0 +1,114 @@
+/*
+ * 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 interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "4".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_content_nameA_crc32c.txt > y
+ * 3) vim -b y
+ * 4) :%!xxd -p -c 4
+ * 5) Delete the frist 44 bytes (11 lines). The first line should now be:
+ * 00020015
+ * 6) Delete the last 8 bytes
+ * The last line two lines should be:
+ * 04000200
+ * 00
+ * What's left is the part to be signed.
+ * 7) :%!xxd -r -p -c 4
+ * 8) :wq
+ * 9) dump the file to one long URL-escaped hex string with
+ * xxd -p -c 256 y | sed 's/[0-9a-f]\{2\}/%&/g'
+ * 10) Copy the hex string to the website and use the settings specified above (don't use 0x in front
+ * of any hex strings). Click "compute!"
+ * 11) The answer should be 2C3CC0Af
+ * 12) Put the byte array from (11) in the Validation Payload.
+ *
+ */
+
+#ifndef v1_content_nameA_crc32c_h
+#define v1_content_nameA_crc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+__attribute__((unused))
+static uint8_t v1_content_nameA_crc32c[] = {
+ 0x01, 0x01, 0x00, 85, // ver = 1, type = content object, length = 85
+ 0x00, 0x00, 0x00, 44, // HopLimit = 31, reserved = 0, header length = 44
+ // ------------------------
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20
+ 0x12, 0x23, 0x34, 0x45,
+ 0x56, 0x67, 0x78, 0x89, // fragid 0x1223344556677889
+ 0x05, 0xDC, 0x01, 0x00, // MTU 1500, fragcnt 1, fragnum 0
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // interest fragment 0x0102030405060708
+ // ------------------------
+ 0x00, 0x02, 0x00, 8, // Recommended Cache Time
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x6D, 0xDD, 0x00, // 2 hours (0x6DDD00 milli seconds)
+ // ------------------------
+ 0x00, 0x02, 0x00, 21, // type = content object, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x2C, 0x3C, 0xC0, 0xAF // 2C3CC0AF
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameA_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } },
+
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 48, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 52, 17 } },
+
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 73, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 81, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameA_crc32c_truthTable TABLEENTRY(v1_content_nameA_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_content_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h
new file mode 100644
index 00000000..ef37fb5e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h
@@ -0,0 +1,181 @@
+/*
+ * 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 interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Signature generated using "openssl sha -sign test_rsa_key.pem -sha256 -binary y > sig", where "y" is
+ * generated from the "xxd -r" of the message hex dump. You need to manually edit "y" so it only
+ * contains the parts begin signed. Then use "xxd -i sig" to get the byte array.
+ *
+ * you can get the dump from the "write_packets" command. here's the detailed steps:
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_content_nameA_keyid1_rsasha256.txt > y
+ * 3) vim -b y
+ * 4) :%!xxd -p -c 16
+ * 5) Delete the frist 32 bytes (2 lines). The first line should now be:
+ * 0002003a000000110002000568656c6c
+ * 6) Delete the last 132 bytes (9 lines, 8 full lines plus the last 4 byte line)
+ * The last line in the file should now be:
+ * 0f3592ae7027fbd2e41e270203010001
+ * What's left is the part to be signed.
+ * 7) :%!xxd -r -p -c 16
+ * 8) :wq
+ * 9) Copy the PEM blocks below and put them in the file "key.pem". Make sure to remove
+ * any leading whitespace. If you get an error in the next command like
+ * "53999:error:0906D06C:PEM routines:PEM_read_bio:no start ... 648:Expecting: ANY PRIVATE KEY" then
+ * you most likely have leading whitespace. Make sure all lines are flush left.
+ * 10) openssl sha -sign key.pem -sha256 -binary y > sig
+ * 11) xxd -i sig
+ * 12) Put the byte array from (11) in the Validation Payload. Verify the length, it should be
+ * 128 bytes. If not, fixup the length of the ValidatonPayload and the PacketLength.
+ *
+ */
+
+/*
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8
+ * V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD
+ * 6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB
+ * AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N
+ * zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj
+ * 83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA
+ * r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3
+ * ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC
+ * 3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6
+ * n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL
+ * U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ
+ * ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ
+ * PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ=
+ * -----END RSA PRIVATE KEY-----
+ *
+ * -----BEGIN PUBLIC KEY-----
+ * MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0E
+ * AY+Ddz+xZqFauTkqsj4w+xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEO
+ * JEKN5nWgTgRDDD5MBnRnrYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8q
+ * PD0PNZKucCf70uQeJwIDAQAB
+ * -----END PUBLIC KEY-----
+ */
+
+#ifndef v1_content_nameA_keyid1_rsasha256_h
+#define v1_content_nameA_keyid1_rsasha256_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+
+__attribute__((unused))
+static uint8_t v1_content_nameA_keyid1_rsasha256[] = {
+ 0x01, 0x01, 0x01, 0xB4,// ver = 1, type = content object, length = 436
+ 0x00, 0x00, 0x00, 32, // HopLimit = 0, reserved = 0, header length = 32
+ // ------------------------
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20
+ 0x12, 0x23, 0x34, 0x45,
+ 0x56, 0x67, 0x78, 0x89,// fragid 0x1223344556677889
+ 0x05, 0xDC, 0x01, 0x00,// MTU 1500, fragcnt 1, fragnum 0
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,// interest fragment 0x0102030405060708
+ // ------------------------
+ 0x00, 0x02, 0x00, 58, // type = content object, length = 58
+ // ------------------------
+ 0x00, 0x00, 0x00, 17, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05,// type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04,// type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x05, 0x00, 1, // PayloadType
+ 1, // type 1 = key
+ 0x00, 0x06, 0x00, 0x08,// expiry time in msec
+ 0x00, 0x00, 0x01, 0x43,// 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ 0x00, 0x19, 0x00, 4, // end chunk number
+ 0x06, 0x05, 0x04, 0x03,
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // payload, length = 8
+ 0x73, 0x75, 0x72, 0x70,
+ 0x72, 0x69, 0x73, 0x65,
+ // ------------------------
+ 0x00, 0x03, 0x00, 206, // validation alg, length = 206
+ 0x00, 0x06, 0x00, 202, // RSA-SHA256, length = 162 + 4 + 32 + 4 = 202
+ 0x00, 0x09, 0x00, 32, // type = keyid, length = 32
+ 0x5c, 0x23, 0x4c, 0x28,
+ 0x50, 0xda, 0x20, 0x7b,
+ 0x88, 0x25, 0x8b, 0xf3,
+ 0x62, 0x61, 0x96, 0xd8,
+ 0xf0, 0x60, 0x76, 0x38,
+ 0xa2, 0xd4, 0xe0, 0xe2,
+ 0x49, 0xb2, 0xa9, 0xaf,
+ 0xce, 0xb8, 0x85, 0x59,
+ 0x00, 0x0B, 0x00, 162, // public key, length = 162
+ 0x30, 0x81, 0x9f, 0x30,0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01,0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+ 0x89, 0x02, 0x81, 0x81,0x00, 0xa7, 0xd6, 0x93, 0xc5, 0xf1, 0x73, 0xc6,
+ 0x12, 0xb5, 0xfa, 0x79,0xc5, 0xef, 0x18, 0x8b, 0xef, 0xaa, 0xcd, 0x04,
+ 0x01, 0x8f, 0x83, 0x77,0x3f, 0xb1, 0x66, 0xa1, 0x5a, 0xb9, 0x39, 0x2a,
+ 0xb2, 0x3e, 0x30, 0xfb,0x11, 0xfc, 0x57, 0xfc, 0x9d, 0xd1, 0x2f, 0x77,
+ 0xf0, 0xab, 0x77, 0xad,0x66, 0x2c, 0x26, 0xc8, 0x9b, 0x51, 0x6f, 0x69,
+ 0xbf, 0x26, 0x10, 0x06,0x29, 0xee, 0xcb, 0xb0, 0x2c, 0x5e, 0x91, 0x0e,
+ 0x24, 0x42, 0x8d, 0xe6,0x75, 0xa0, 0x4e, 0x04, 0x43, 0x0c, 0x3e, 0x4c,
+ 0x06, 0x74, 0x67, 0xad,0x84, 0xc3, 0xe8, 0xf4, 0xc5, 0x94, 0x73, 0xc4,
+ 0x9f, 0x25, 0xa8, 0x42,0x06, 0xbf, 0x45, 0x19, 0xe2, 0x98, 0x1c, 0x36,
+ 0xa1, 0x43, 0x4d, 0x9b,0x71, 0x08, 0xe1, 0x82, 0xdf, 0xe2, 0x4f, 0x2a,
+ 0x3c, 0x3d, 0x0f, 0x35,0x92, 0xae, 0x70, 0x27, 0xfb, 0xd2, 0xe4, 0x1e,
+ 0x27, 0x02, 0x03, 0x01,0x00, 0x01,
+ // ------------------------
+ 0x00, 0x04, 0x00, 128, // validation payload, length = 128
+ 0x03, 0x46, 0xee, 0xb7,0x30, 0x1c, 0xea, 0x13, 0x0c, 0xce, 0x83, 0x5b,
+ 0x7b, 0x4f, 0xf5, 0x83,0x37, 0x08, 0x7f, 0xe0, 0xe1, 0xc9, 0x70, 0x09,
+ 0x5e, 0xc2, 0x1c, 0xd3,0x74, 0xbb, 0xbd, 0x72, 0x35, 0xa4, 0x1b, 0x0f,
+ 0x3d, 0x04, 0x5e, 0xf7,0xc1, 0xdf, 0xea, 0xc3, 0x50, 0x47, 0x14, 0xf9,
+ 0xb7, 0xbb, 0x42, 0xf9,0x3e, 0xaa, 0x49, 0xd2, 0x9f, 0xd1, 0xab, 0xf6,
+ 0xda, 0x32, 0x4a, 0xb1,0xb9, 0x69, 0x91, 0x57, 0x43, 0x5d, 0x06, 0xcf,
+ 0x1d, 0x9f, 0x7c, 0x28,0xee, 0x35, 0xaa, 0xd0, 0xb2, 0x8d, 0x34, 0x09,
+ 0xcd, 0xdb, 0x01, 0xf7,0xda, 0xe8, 0x59, 0x98, 0x4e, 0x59, 0xfa, 0x13,
+ 0xd0, 0xd1, 0x54, 0x8e,0x64, 0x8c, 0xc6, 0xd7, 0x6b, 0xc5, 0x89, 0xeb,
+ 0x37, 0x8f, 0x53, 0x04,0xba, 0x03, 0x05, 0xb4, 0x67, 0x73, 0xe1, 0x51,
+ 0x59, 0x12, 0xbc, 0x25,0xaa, 0xa2, 0xc1, 0x18
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 36, 58 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 40, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 61, 1 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 66, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 78, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 86, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 94, 206 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_KEYID, .bodyManifest = true, .extent = { 106, 32 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PUBKEY, .bodyManifest = true, .extent = { 142, 162 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 308, 128 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameA_keyid1_rsasha256_truthTable TABLEENTRY(v1_content_nameA_keyid1_rsasha256, TLV_ERR_NO_ERROR)
+
+#define v1_content_nameA_keyid1_rsasha256_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h
new file mode 100644
index 00000000..f1fc59cb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h
@@ -0,0 +1,65 @@
+/*
+ * 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 v1_content_nameless_nosig.h
+ * @brief A v1 content object without a name
+ *
+ */
+
+#ifndef v1_content_nameless_nosig_h
+#define v1_content_nameless_nosig_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed nameless V1 Content Object
+ */
+__attribute__((unused))
+static uint8_t v1_content_nameless_nosig[] = {
+ 0x01, 0x01, 0x00, 0x31, // ver = 1, type = content object, length = 0x31
+ 0x00, 0x00, 0x00, 0x08, // HopLimit = 0, reserved = 0, header length = 8
+ // ------------------------
+ 0x00, 0x02, 0x00, 37, // type = content object, length = 37
+ // ------------------------
+ 0x00, 0x05, 0x00, 1, // PayloadType
+ 1, // type 1 = key
+ 0x00, 0x06, 0x00, 0x08, // expiry time in msec
+ 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ 0x00, 0x19, 0x00, 4, // end chunk number
+ 0x06, 0x05, 0x04, 0x03,
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // payload, length = 8
+ 0x73, 0x75, 0x72, 0x70,
+ 0x72, 0x69, 0x73, 0x65,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameless_nosig)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 37 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 17, 1 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 22, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 30, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 41, 8 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameless_nosig_truthTable TABLEENTRY(v1_content_nameless_nosig, TLV_ERR_NO_ERROR)
+
+#endif // v1_content_nameless_nosig_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h
new file mode 100644
index 00000000..ae439bf5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h
@@ -0,0 +1,55 @@
+/*
+ * 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 v1_content_no_payload.h
+ * @brief Content Object without a payload TLV
+ *
+ *
+ */
+
+
+#ifndef CCNx_Common_v1_content_no_payload_h
+#define CCNx_Common_v1_content_no_payload_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_content_no_payload[] = {
+ 0x01, 0x01, 0x00, 0x21,
+ 0x00, 0x00, 0x00, 0x08,
+ // -- content object
+ 0x00, 0x02, 0x00, 0x15,
+ // -- name
+ 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x03, 0x00, 0x02,
+ 0x6e, 0x6f,
+ 0x00, 0x03, 0x00, 0x07,
+ 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_no_payload)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 21 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_no_payload_truthTable TABLEENTRY(v1_content_no_payload, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h
new file mode 100644
index 00000000..01f7a8b4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h
@@ -0,0 +1,57 @@
+/*
+ * 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 v1_content_zero_payload.h
+ * @brief Content Object with zero length payload
+ *
+ *
+ */
+
+
+#ifndef CCNx_Common_v1_content_zero_payload_h
+#define CCNx_Common_v1_content_zero_payload_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_content_zero_payload[] = {
+ 0x01, 0x01, 0x00, 0x25,
+ 0x00, 0x00, 0x00, 0x08,
+ // -- content object
+ 0x00, 0x02, 0x00, 0x19,
+ // -- name
+ 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x03, 0x00, 0x02,
+ 0x6e, 0x6f,
+ 0x00, 0x03, 0x00, 0x07,
+ 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64,
+ // -- payload
+ 0x00, 0x01, 0x00, 0x00,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_zero_payload)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 25 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_zero_payload_truthTable TABLEENTRY(v1_content_zero_payload, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h
new file mode 100644
index 00000000..9bcf7dfc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h
@@ -0,0 +1,50 @@
+/*
+ * 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 v1_cpi_add_route.h
+ * @brief A hand-encoded CPI packet to add a route
+ *
+ * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string.
+ * The packet type is 0xA4.
+ *
+ */
+
+#ifndef TransportRTA_v1_cpi_AddRoute_h
+#define TransportRTA_v1_cpi_AddRoute_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h>
+
+__attribute__((unused))
+static uint8_t v1_cpi_add_route[] = "\x01\xA4\x00\xA7"
+ "\x00\x00\x00\x08"
+ "\xBE\xEF\x00\x9A"
+ "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_cpi_add_route)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_cpi_add_route_truthTable TABLEENTRY(v1_cpi_add_route, TLV_ERR_NO_ERROR)
+
+#define v1_cpi_add_route_PrefixUri "lci:/howdie/stranger"
+#define v1_cpi_add_route_Sequence 22
+#define v1_cpi_add_route_Interface 55
+#endif // TransportRTA_cpi_AddRoute_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h
new file mode 100644
index 00000000..e31cfc85
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h
@@ -0,0 +1,78 @@
+/*
+ * 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 v1_cpi_add_route.h
+ * @brief A hand-encoded CPI packet to add a route
+ *
+ * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string.
+ * The packet type is 0xA4.
+ *
+ * This control packet has a CRC32C MIC on it. Otherwise, same as v1_cpi_add_route.h
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "4".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_cpi_add_route_crc32c.txt > y
+ * 3) Delete the first 8 bytes and last 16 bytes and display has a hex string
+ * tail -c +9 y | head -c 158 | xxd -p -c 256
+ * The string should be "beef...077d7d7d"
+ * 4) The string for this packet is too long for the website. Use another tool such as reveng.
+ * 5) The answer should be 78fd926a (the reveng answer will be byte reversed)
+ * 6) Put the byte array from (5) in the Validation Payload.
+ *
+ */
+
+#ifndef TransportRTA_v1_v1_cpi_AddRoute_crc32c_h
+#define TransportRTA_v1_v1_cpi_AddRoute_crc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h>
+
+__attribute__((unused))
+static uint8_t v1_cpi_add_route_crc32c[] = "\x01\xA4\x00\xB7"
+ "\x00\x00\x00\x08"
+ "\xBE\xEF\x00\x9A"
+ "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"
+ "\x00\x03\x00\x04"
+ "\x00\x02\x00\x00"
+ "\x00\x04\x00\x04"
+ "\x78\xfd\x92\x6a";
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_cpi_add_route_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_ValidationAlg, .bodyManifest = true, .extent = { 171, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_SIGBITS, .bodyManifest = true, .extent = { 178, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_cpi_add_route_crc32c_truthTable TABLEENTRY(v1_cpi_add_route_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_cpi_add_route_crc32c_PrefixUri "lci:/howdie/stranger"
+#define v1_cpi_add_route_crc32c_Sequence 22
+#define v1_cpi_add_route_crc32c_Interface 55
+#endif // TransportRTA_cpi_AddRoute_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h
new file mode 100755
index 00000000..f6524ad1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h
@@ -0,0 +1,102 @@
+/*
+ * 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 v1_interest_all_fields.h
+ * @brief A hand-encoded v1 interest in wireformat with all Interest fields.
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef CCNx_Common_v1_interest_all_fields_h
+#define CCNx_Common_v1_interest_all_fields_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with all allowed Interest fields
+ */
+__attribute__((unused))
+static uint8_t v1_interest_all_fields[] = {
+ 0x01, 0x00, 0x00, 156, // ver = 1, type = interest, length = 156
+ 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 138, // type = interest, length = 138
+ // ------------------------
+ 0x00, 0x00, 0x00, 45, // type = name, length = 45
+ 0x00, 0x03, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+ // ----- segment 2 --------
+ 0x00, 0x02, 0x00, 33, // type = payload id, length = 33
+ 0x01, // payloadID type = sha256
+ 0x89, 0x87, 0x69, 0xfc, // hash bytes based on payload
+ 0x8c, 0xff, 0x16, 0xff,
+ 0x3d, 0xfc, 0xe7, 0xfa,
+ 0x02, 0xd2, 0x6d, 0x26,
+ 0xf0, 0x91, 0x86, 0x27,
+ 0xcf, 0x18, 0xc1, 0x9b,
+ 0x0b, 0x5f, 0xe3, 0x93,
+ 0xce, 0x1a, 0xa3, 0x56,
+ // ------------------------
+ 0x00, 0x02, 0x00, 36, // type = keyid restriction, length = 36
+ 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ // ------------------------
+ 0x00, 0x03, 0x00, 36, // type = hash restriction, length = 36
+ 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb,
+ 0xcc, 0xcd, 0xce, 0xcf,
+ // ------------------------
+ 0x00, 0x01, 0x00, 5, // type = payload, length = 5
+ 0xD0, 0xD1, 0xD2, 0xD3,
+ 0xD4,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_all_fields)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 12, 2 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 18, 138 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 22, 45 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_KEYID, .bodyManifest = true, .extent = { 71, 36 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_OBJHASH, .bodyManifest = true, .extent = { 111, 36 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_PAYLOAD, .bodyManifest = true, .extent = { 151, 5 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_all_fields_truthTable TABLEENTRY(v1_interest_all_fields, TLV_ERR_NO_ERROR)
+
+#define v1_interest_all_fields_URI "lci:/3=cool/2=\x01\x89\x87\x69\xfc\x8c\xff\x16\xff\x3d\xfc\xe7\xfa\x02\xd2\x6d\x26\xf0\x91\x86\x27\xcf\x18\xc1\x9b\x0b\x5f\xe3\x93\xce\x1a\xa3\x56"
+#define v1_interest_all_fields_Lifetime 0xEAEB
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h
new file mode 100644
index 00000000..650c770e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h
@@ -0,0 +1,57 @@
+/*
+ * 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 v1_interest_all_fields.h
+ * @brief A hand-encoded v1 interest in wireformat with all Interest fields.
+ *
+ * The Interest TLV length goes beyond the end of the packet
+ *
+ */
+
+#ifndef CCNx_Common_v1_interest_bad_message_length_h
+#define CCNx_Common_v1_interest_bad_message_length_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with all allowed Interest fields
+ */
+__attribute__((unused))
+static uint8_t v1_interest_bad_message_length[] = {
+ 0x01, 0x00, 0x00, 30, // ver = 1, type = interest, length = 30
+ 0x20, 0x00, 0x11, 14, // HopLimit = 31, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 13, // type = interest, length = 13 (1 byte too far)
+ // ------------------------
+ 0x00, 0x00, 0x00, 8, // type = name, length = 8
+ 0x00, 0x03, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_bad_message_length)[] =
+{
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_bad_message_length_truthTable TABLEENTRY(v1_interest_bad_message_length, TLV_ERR_TOO_LONG)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h
new file mode 100644
index 00000000..9c4c3117
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h
@@ -0,0 +1,74 @@
+/*
+ * 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 v1_interest_bad_validation_alg.h
+ * @brief Interest with CRC validation
+ *
+ * This is an error packet, the ValidationAlg TLV does not have the correct type
+ *
+ */
+
+#ifndef testdata_v1_interest_bad_validation_alg
+#define testdata_v1_interest_bad_validation_alg
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_interest_bad_validation_alg[] = {
+ 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0xFF, 0x00, 4, // Not "0x03" validation alg length = 4
+ 0x00, 0xFF, 0x00, 0x00, // unknown validation alg
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_bad_validation_alg)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_bad_validation_alg_truthTable TABLEENTRY(v1_interest_bad_validation_alg, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h
new file mode 100644
index 00000000..4bee1e40
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h
@@ -0,0 +1,75 @@
+/*
+ * 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 v1_interest_nameA.h
+ * @brief A basic interest
+ *
+ * A basic Interest with a fragmentation header and Name.
+ *
+ */
+
+#ifndef testdata_interest_nameA_h
+#define testdata_interest_nameA_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA[] = {
+ 0x01, 0x00, 0x00, 61, // ver = 1, type = interest, length = 61
+ 0x20, 0x00, 0x00, 36, // HopLimit = 31, reserved = 0, header length = 36
+ // ------------------------
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // Interest Lifetime
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0F, 0xA0, // 4000 milli-seconds
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = false, .extent = { 40, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 44, 17 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_nameA_truthTable TABLEENTRY(v1_interest_nameA, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h
new file mode 100644
index 00000000..6af04f42
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h
@@ -0,0 +1,76 @@
+/*
+ * 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 interest_nameA_badcrc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Has incorrect CRC32C payload
+ *
+ */
+
+#ifndef testdata_interest_nameA_badcrc32c_h
+#define testdata_interest_nameA_badcrc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_badcrc32c[] = {
+ 0x01, 0x00, 0x00, 41, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 31, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 0x0C, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x00, 0x00, 0x00, 0x00 // invalid CRC32C
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA_badcrc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 20, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 24, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 45, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_nameA_badcrc32c_truthTable TABLEENTRY(v1_interest_nameA_badcrc32c, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_badcrc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h
new file mode 100644
index 00000000..64edf560
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h
@@ -0,0 +1,102 @@
+/*
+ * 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 interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e (the output will be backwards)
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 8 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "8".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_interest_nameA_crc32c.txt > y
+ * 3) Delete the first 24 bytes and last 8 bytes and display as a URI-escaped hex string
+ * head -c 57 y | tail -c +25 | xxd -p -c 256 | sed 's/[0-9a-f]\{2\}/%&/g'
+ * The string should be "00010015...00020000"
+ * 4) Copy the hex string to the website and use the settings specified above (don't use 0x in front
+ * of any hex strings). IMPORTANT: you need to %-escape each hex byte!! Click "compute!"
+ * 5) The answer should be 6AD7B1F2
+ * 6) Put the byte array from (5) in the Validation Payload.
+ *
+ */
+
+#ifndef testdata_interest_nameA_crc32c_h
+#define testdata_interest_nameA_crc32c_h
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+#define NAME_A_CRC32_PACKET(_type, _code) \
+ { \
+ 0x01, _type, 0x00, 65, /* ver = 1, type = interest, length = 65 */ \
+ 0x20, _code, 0x00, 24, /* HopLimit = 32, reserved = 0, header length = 24*/ \
+ /* ------------------------ */ \
+ 0x00, 0x03, 0x00, 12, /* Interest Fragment */ \
+ 0x01, 0x02, 0x03, 0x04, \
+ 0x05, 0x06, 0x07, 0x08, /* fragment 0x0102030405060708 */ \
+ 0x05, 0xDC, 0x00, 0x00, /* MTU 1500, fragcnt 0, fragnum 0 */ \
+ /* ------------------------ */ \
+ 0x00, 0x01, 0x00, 0x15, /* type = interest, length = 21 */ \
+ /* ------------------------ */ \
+ 0x00, 0x00, 0x00, 0x11, /* type = name, length = 17 */ \
+ 0x00, 0x03, 0x00, 0x05, /* type = binary, length = 5 */ \
+ 'h', 'e', 'l', 'l', /* "hello" */ \
+ 'o', \
+ 0xF0, 0x00, 0x00, 0x04, /* type = app, length = 4 */ \
+ 'o', 'u', 'c', 'h', /* "ouch" */ \
+ /* ------------------------ */ \
+ 0x00, 0x03, 0x00, 4, /* validation alg, length = 4 */ \
+ 0x00, 0x02, 0x00, 0x00, /* CRC32C */ \
+ /* ------------------------ */ \
+ 0x00, 0x04, 0x00, 4, /* validation payload */ \
+ 0xD0, 0x98, 0x73, 0x7C, /* D098737C */ \
+ }
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_crc32c[] = NAME_A_CRC32_PACKET(0x00, 0x00);
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_crc32c_returned[] = NAME_A_CRC32_PACKET(0x02, 0x03); //InterestReturn & NoResource
+
+#define v1_interest_nameA_crc32c_truthTable TABLEENTRY(v1_interest_nameA_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h
new file mode 100644
index 00000000..8f3b55a5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h
@@ -0,0 +1,74 @@
+/*
+ * 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 v1_interest_validation_alg_overrun.h
+ * @brief Interest with CRC validation
+ *
+ * This is an error packet. The length of the Validation TLV runs past the end of the packet.
+ *
+ */
+
+#ifndef testdata_v1_interest_validation_alg_overrun
+#define testdata_v1_interest_validation_alg_overrun
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_interest_validation_alg_overrun[] = {
+ 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 255, // Validation Alg, length = 255
+ 0x00, 0xFF, 0x00, 0x00, // unknown validation alg
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_validation_alg_overrun)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_validation_alg_overrun_truthTable TABLEENTRY(v1_interest_validation_alg_overrun, TLV_ERR_TOO_LONG)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h
new file mode 100644
index 00000000..f98de878
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains tables of all the packets. May be used for automated testing. Also used by write_packets utility.
+ *
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+
+#include "v1_interest_nameA.h"
+#include "v1_interest_nameA_badcrc32c.h"
+#include "v1_interest_nameA_crc32c.h"
+#include "v1_interest_bad_validation_alg.h"
+#include "v1_interest_validation_alg_overrun.h"
+
+#include "v1_content_nameA_crc32c.h"
+#include "v1_content_nameA_keyid1_rsasha256.h"
+#include "v1_content_zero_payload.h"
+#include "v1_content_no_payload.h"
+
+#include "v1_cpi_add_route.h"
+#include "v1_cpi_add_route_crc32c.h"
+
+// terminated with NULL packet entry
+__attribute__((unused))
+static TruthTable v1_interests_truthSet [] = {
+ // tests in alphabetical order
+ v1_interest_nameA_truthTable,
+ v1_interest_nameA_badcrc32c_truthTable,
+ v1_interest_nameA_crc32c_truthTable,
+ v1_interest_bad_validation_alg_truthTable,
+ v1_interest_validation_alg_overrun_truthTable,
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
+
+// terminated with NULL packet entry
+__attribute__((unused))
+static TruthTable v1_contentObject_truthSet [] = {
+ v1_content_nameA_crc32c_truthTable,
+ v1_content_nameA_keyid1_rsasha256_truthTable,
+ v1_content_zero_payload_truthTable,
+ v1_content_no_payload_truthTable,
+
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
+
+__attribute__((unused))
+static TruthTable v1_cpi_truthSet [] = {
+ v1_cpi_add_route_truthTable,
+ v1_cpi_add_route_crc32c_truthTable,
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h
new file mode 100755
index 00000000..32c954b7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * testrig_truthTable.h
+ * TransportRTA
+ */
+
+#ifndef TransportRTA_testrig_truthTable_h
+#define TransportRTA_testrig_truthTable_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_CPISchema.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/test/.gitignore b/libccnx-common/ccnx/common/codec/test/.gitignore
new file mode 100644
index 00000000..f0d97bc9
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/.gitignore
@@ -0,0 +1,7 @@
+test_ccnxCodec_EncodingBuffer
+test_ccnxCodec_Error
+test_ccnxCodec_NetworkBuffer
+test_ccnxCodec_TlvDecoder
+test_ccnxCodec_TlvEncoder
+test_ccnxCodec_TlvPacket
+test_ccnxCodec_TlvUtilities
diff --git a/libccnx-common/ccnx/common/codec/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt
new file mode 100644
index 00000000..73dd544e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+configure_file(test_rsa.p12 test_rsa.p12 COPYONLY)
+configure_file(test_random_bytes test_random_bytes COPYONLY)
+configure_file(test_random_bytes.sig test_random_bytes.sig COPYONLY)
+configure_file(test_rsa_key.pem test_rsa_key.pem COPYONLY)
+
+set(TestsExpectedToPass
+ test_ccnxCodec_EncodingBuffer
+ test_ccnxCodec_Error
+ test_ccnxCodec_NetworkBuffer
+ test_ccnxCodec_TlvDecoder
+ test_ccnxCodec_TlvEncoder
+ test_ccnxCodec_TlvPacket
+ test_ccnxCodec_TlvUtilities
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c
new file mode 100755
index 00000000..33bdbbc7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c
@@ -0,0 +1,343 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_EncodingBuffer.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ CCNxCodecEncodingBuffer *encodingBuffer;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxCodecEncodingBuffer_Release(&data->encodingBuffer);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodec_EncodingBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodec_EncodingBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodec_EncodingBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 0, "Wrong position, got %zu expected %d", position, 0);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 1, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 1);
+ assertTrue(data->encodingBuffer->totalBytes == 5, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 5);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+
+ // do two appends
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 1, "Wrong position, got %zu expected %d", position, 1);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2);
+ assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10);
+
+ // should still be in the first listarray
+ assertTrue(data->encodingBuffer->head == data->encodingBuffer->tail, "Head != tail")
+ {
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+ }
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+
+ // now fake out the list array so it thinks its full.
+ // Do this by reducing the capacity so there are no undefined buffers on the list
+ data->encodingBuffer->head->capacity = data->encodingBuffer->head->count;
+
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 1, "Wrong position, got %zu expected %u", position, 1);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2);
+ assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10);
+
+ // should now have different head and tail
+ assertTrue(data->encodingBuffer->head != data->encodingBuffer->tail, "Head == tail")
+ {
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+ }
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->encodingBuffer, "Got null buffer from create");
+ assertNull(data->encodingBuffer->head, "buffer head is not null");
+ assertNull(data->encodingBuffer->tail, "Buffer tail is not null");
+ assertTrue(data->encodingBuffer->totalCount == 0, "Buffer itemCount is not 0");
+ assertTrue(data->encodingBuffer->totalBytes == 0, "Buffer totalBytes is not 0");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+ ccnxCodecEncodingBuffer_PrependBuffer(data->encodingBuffer, buffer_1);
+
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer);
+ assertNotNull(iov, "Got null iov from CreateIOVec");
+ assertTrue(iov->iovcnt == 2, "Wrong iovec count, got %d expected %d", iov->iovcnt, 2);
+ assertTrue(iov->iov[0].iov_base == foo, "WRong iov[0].iov_base, got %p exected %p", iov->iov[0].iov_base, foo);
+ assertTrue(iov->iov[1].iov_base == bar, "WRong iov[1].iov_base, got %p exected %p", iov->iov[1].iov_base, bar);
+ assertTrue(iov->iov[0].iov_len == sizeof(foo), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[0].iov_len, sizeof(foo));
+ assertTrue(iov->iov[1].iov_len == sizeof(bar), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[1].iov_len, sizeof(bar));
+
+ // Slice crossing two iovec arrays
+ CCNxCodecEncodingBuffer *bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 6);
+ CCNxCodecEncodingBufferIOVec *iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2);
+ assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1);
+ assertTrue(iovSlice->iov[0].iov_len == sizeof(foo) - 1, "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo) - 1);
+ assertTrue(iovSlice->iov[1].iov_len == 6 - (sizeof(foo) - 1), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, 6 - (sizeof(foo) - 1));
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ // Slice within one iovec array
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 1);
+ iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 1, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 1);
+ assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1);
+ assertTrue(iovSlice->iov[0].iov_len == 1, "WRong iovSlice[1].iov_len, got %zu exected %d", iovSlice->iov[0].iov_len, 1);
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ // Slice beyond contents
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, sizeof(foo) + sizeof(bar), 1);
+ assertNull(bufferSlice, "ccnxCodecEncodingBuffer_Slice returned allocation for slice outside of buffer");
+
+ // Slice including all and beyond
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 0, sizeof(foo) + sizeof(bar) + 10);
+ iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2);
+ assertTrue(iovSlice->iov[0].iov_base == foo, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo);
+ assertTrue(iovSlice->iov[0].iov_len == sizeof(foo), "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo));
+ assertTrue(iovSlice->iov[1].iov_len == sizeof(bar), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, sizeof(bar));
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer);
+ assertNotNull(iov, "Got null iov from CreateIOVec");
+ assertTrue(iov->iovcnt == 0, "Wrong iovec count, got %d expected %d", iov->iovcnt, 0);
+
+ // single allocation means that the iov will never be null
+ assertNotNull(iov->iov, "iov->iov should not be null");
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+
+ size_t length = ccnxCodecEncodingBuffer_Length(data->encodingBuffer);
+ size_t truth = sizeof(foo) + sizeof(bar);
+ assertTrue(length == truth, "Wrong length, got %zu expected %zu", length, truth);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Size)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+
+ size_t size = ccnxCodecEncodingBuffer_Size(data->encodingBuffer);
+ assertTrue(size == 2, "Wrong size, got %zu expected %u", size, 2);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Example)
+{
+ PARCBuffer *name = parcBuffer_Wrap("marc", 4, 0, 4);
+ PARCBuffer *space = parcBuffer_Wrap(" ", 1, 0, 1);
+ PARCBuffer *email = parcBuffer_Wrap("<marc@example.com>", 18, 0, 18);
+
+ CCNxCodecEncodingBuffer *encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, name);
+ ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, space);
+ parcBuffer_Release(&space);
+ parcBuffer_Release(&name);
+
+ CCNxCodecEncodingBuffer *emailBuffer = ccnxCodecEncodingBuffer_Create();
+ ccnxCodecEncodingBuffer_AppendBuffer(emailBuffer, email);
+ parcBuffer_Release(&email);
+
+ ccnxCodecEncodingBuffer_Release(&emailBuffer);
+
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(encodingBuffer);
+ ssize_t nwritten = writev(STDOUT_FILENO, iov->iov, iov->iovcnt);
+ assertTrue(nwritten > -1, "Error writev");
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+
+ ccnxCodecEncodingBuffer_Release(&encodingBuffer);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodec_EncodingBuffer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c
new file mode 100755
index 00000000..1fee88c3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c
@@ -0,0 +1,139 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_Error.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(tlv_Errors)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(tlv_Errors)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(tlv_Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetByteOffset);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetLine);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetFunction);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorMessage);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_Create_Destroy)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ ccnxCodecError_Release(&error);
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetByteOffset)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetByteOffset(error) == 100,
+ "Wrong offset, expected %u got %zu",
+ 100,
+ ccnxCodecError_GetByteOffset(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorCode)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetErrorCode(error) == TLV_ERR_NO_ERROR,
+ "Wrong error code, expected %d got %d",
+ TLV_ERR_NO_ERROR,
+ ccnxCodecError_GetErrorCode(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetLine)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetLine(error) == 10,
+ "Wrong line number, expected %d got %d",
+ 10,
+ ccnxCodecError_GetLine(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetFunction)
+{
+ char *apple = "apple";
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100);
+ assertTrue(ccnxCodecError_GetFunction(error) == apple,
+ "Wrong function string, expected %p got %p",
+ apple,
+ ccnxCodecError_GetFunction(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorMessage)
+{
+ char *apple = "apple";
+ const char *truth = ccnxCodecErrors_ErrorMessage(TLV_ERR_NO_ERROR);
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100);
+ assertTrue(ccnxCodecError_GetErrorMessage(error) == truth,
+ "Wrong function string, expected %p got %p",
+ truth,
+ ccnxCodecError_GetErrorMessage(error));
+ ccnxCodecError_Release(&error);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(tlv_Errors);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c
new file mode 100755
index 00000000..aec3018e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c
@@ -0,0 +1,952 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_NetworkBuffer.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+typedef struct test_data {
+ CCNxCodecNetworkBuffer *buffer;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxCodecNetworkBuffer_Release(&data->buffer);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_NetworkBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(SetLimit);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_NetworkBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NetworkBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBufferIoVec_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBufferIoVec_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecNetworkBufferIoVec *first = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+ assertTrue(first->refcount == 1, "Wrong refcount, got %u expected %u", first->refcount, 1);
+
+ CCNxCodecNetworkBufferIoVec *second = ccnxCodecNetworkBufferIoVec_Acquire(first);
+ assertTrue(first->refcount == 2, "Wrong refcount, got %u expected %u", first->refcount, 2);
+
+ ccnxCodecNetworkBufferIoVec_Release(&second);
+ ccnxCodecNetworkBufferIoVec_Release(&first);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecNetworkBuffer *second = ccnxCodecNetworkBuffer_Acquire(data->buffer);
+ assertTrue(data->buffer->refcount == 2, "wrong refcount, got %u expected %u", data->buffer->refcount, 2);
+ ccnxCodecNetworkBuffer_Release(&second);
+ assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1);
+}
+
+/*
+ * Uses a test set generated by openssl:
+ * openssl genrsa -out test_rsa_key.pem
+ * openssl rsa -pubout -in test_rsa_key.pem -out test_rsa_pub.pem
+ * openssl req -new -key test_rsa_key.pem -out test_rsa.csr
+ * openssl x509 -req -days 365 -in test_rsa.csr -signkey test_rsa_key.pem -out test_rsa.crt
+ * openssl pkcs12 -export -in test_rsa.crt -inkey test_rsa_key.pem -out test_rsa.p12 -name ccnxuser -CAfile test_rsa.crt -caname root -chain -passout pass:blueberry
+ * openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_random_bytes
+ *
+ * In English: generate a public private key, put it in a PKCS12 file (test_rsa.p12), then use that to sign
+ * a buffer (test_random_bytes) and put the signature in a file (test_random_bytes.sig).
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature)
+{
+ parcSecurity_Init();
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ parcKeyStore_Release(&keyStore);
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd != -1, "Cannot open test_random_bytes file.");
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Put it in a NetworkBuffer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, read_bytes, buffer_to_sign);
+
+ // Sign it
+ PARCSignature *testSignature = ccnxCodecNetworkBuffer_ComputeSignature(data->buffer, 0, ccnxCodecNetworkBuffer_Limit(data->buffer), signer);
+ PARCBuffer *testBytes = parcSignature_GetSignature(testSignature);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ assertTrue(fd != -1, "Cannot open test_random_bytes.sig file.");
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBuffer *truth = parcBuffer_Wrap(scratch_buffer, read_bytes, 0, read_bytes);
+
+ assertTrue(parcBuffer_Equals(testBytes, truth), "Signatures do not match")
+ {
+ parcBuffer_Display(testBytes, 0);
+ parcBuffer_Display(truth, 0);
+ }
+
+ parcBuffer_Release(&truth);
+ parcSignature_Release(&testSignature);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->buffer, "null buffer");
+ assertTrue(data->buffer->head == data->buffer->current && data->buffer->current == data->buffer->tail,
+ "wrong pointers, head should equal current should equal tail");
+ assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1);
+ assertTrue(data->buffer->position == 0, "wrong position, got %zu expected %u", data->buffer->position, 1);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray)
+{
+ size_t length = 64;
+ uint8_t *memory = parcMemory_Allocate(length);
+ assertNotNull(memory, "parcMemory_Allocate(%zu) returned NULL", length);
+ for (int i = 0; i < length; i++) {
+ memory[i] = i * 3;
+ }
+
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, length, memory);
+
+ assertNotNull(netbuff, "Got null from createFromArray");
+
+ PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(netbuff);
+ PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match")
+ {
+ ccnxCodecNetworkBuffer_Display(netbuff, 3);
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(vec->iovcnt == 5, "iovcnt wrong got %d expected %d", vec->iovcnt, 5);
+ assertTrue(vec->totalBytes == 8192, "Wrong total bytes, got %zu expected %u", vec->totalBytes, 8192)
+ {
+ ccnxCodecNetworkBufferIoVec_Display(vec, 3);
+ }
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+/*
+ * not much to do excpet make sure there's no leaks or assertions
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->buffer->position = 22;
+
+ size_t test = ccnxCodecNetworkBuffer_Position(data->buffer);
+ assertTrue(test == 22, "wrong position, got %zu expected %u", test, 22);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+ size_t nextPosition = data->buffer->position + sizeof(array);
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+
+ size_t startPosition = data->buffer->capacity - sizeof(array);
+ size_t nextPosition = startPosition + sizeof(array);
+
+ data->buffer->position = startPosition;
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[startPosition], array, sizeof(array)) == 0, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+
+ // 3 elements in the current block, 3 in the next block
+ size_t startPosition = data->buffer->capacity - 3;
+ size_t nextPosition = startPosition + sizeof(array);
+
+ data->buffer->position = startPosition;
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->head->memory[startPosition], array, 3) == 0, "wrong memory");
+ assertTrue(memcmp(&data->buffer->tail->memory[0], array + 3, 3) == 0, "wrong memory");
+ // and we should have a new buffer
+ assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail");
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ CCNxCodecNetworkBufferMemory *block = data->buffer->head;
+ size_t offset = 0;
+ while (offset < arrayLength) {
+ size_t remaining = (arrayLength - offset > block->capacity) ? block->capacity : arrayLength - offset;
+ assertTrue(memcmp(&block->memory[0], array + offset, remaining) == 0, "wrong memory");
+ offset += remaining;
+ block = block->next;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ size_t nextPosition = data->buffer->position + sizeof(array);
+
+ ccnxCodecNetworkBuffer_PutBuffer(data->buffer, buffer);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory");
+
+ parcBuffer_Release(&buffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint16_t value = 0x2587;
+ size_t nextPosition = data->buffer->position + sizeof(value);
+
+ ccnxCodecNetworkBuffer_PutUint16(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint16_t testValue = htons(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t value = 0xABCDEF0122334455;
+ size_t nextPosition = data->buffer->position + sizeof(value);
+
+ ccnxCodecNetworkBuffer_PutUint64(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint8_t truthValue[] = { 0xAB, 0xCD, 0xEF, 0x01, 0x22, 0x33, 0x44, 0x55 };
+ assertTrue(memcmp(&data->buffer->current->memory[0], truthValue, sizeof(truthValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * Put a uint32 in to a block with plenty of space
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t value = 0xABCDEF01;
+ size_t nextPosition = data->buffer->position + 4;
+
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * The current block only has 2 bytes left and there is no next pointer. Should throw away
+ * those 2 bytes, allocate a new block, then write the whole thing there.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // set limit and position out to capacity -2
+ data->buffer->current->limit = data->buffer->current->capacity - 2;
+ data->buffer->position = data->buffer->current->limit;
+
+ uint32_t value = 0xABCDEF01;
+ size_t nextPosition = data->buffer->position + 4;
+
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * The current block only has 2 bytes left and there is a next block. Because the current
+ * block is frozen, it will need to split the write over the two blocks.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // this is where we'll want to start our write
+ size_t start = data->buffer->current->capacity - 2;
+ size_t nextPosition = start + 4;
+
+ // set limit and position out to capacity then allocate another block
+ data->buffer->current->limit = data->buffer->current->capacity;
+ data->buffer->position = data->buffer->current->limit;
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(data->buffer);
+
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, start);
+ uint32_t value = 0x33445566;
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ // check the value is split between the two buffers
+ assertTrue(memcmp(&data->buffer->head->memory[start], &testValue, 2) == 0, "wrong memory in first buffer")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+
+ assertTrue(memcmp(&data->buffer->tail->memory[0], (uint8_t *) &testValue + 2, 2) == 0, "wrong memory in second buffer")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+
+ uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 0);
+ assertTrue(data->buffer->current->memory[0] == test, "wrong memory, got %u expected %u", test, data->buffer->current->memory[0]);
+}
+
+/*
+ * Write stuff that spans two blocks, then get the uint8 from the second block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock)
+{
+ // Write an array that will span 5 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 4777);
+ assertTrue(test == array[4777], "Data at index 4777 wrong, got %02X expected %02X",
+ test, array[4777]);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+ size_t relativePosition = data->buffer->position - data->buffer->current->begin;
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero)
+{
+ // put the position to just before the end of the buffer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ data->buffer->position = data->buffer->current->capacity - 1;
+ size_t relativePosition = data->buffer->position - data->buffer->current->begin;
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace)
+{
+ // put the position at the end of the current buffer, force an allocation
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ // pretend we've written all the way out to the capacity
+ data->buffer->position = data->buffer->current->capacity;
+ data->buffer->current->limit = data->buffer->current->capacity;
+
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+
+ size_t relativePosition = 0;
+
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+ // and we should have a new buffer
+ assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail");
+}
+
+/*
+ * Set position beyond the limit of what's been written
+ */
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit, .event = &LongBowAssertEvent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit + 1);
+}
+
+/*
+ * Set position to good location that is in the current block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, 0x12345678);
+
+ size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit - 1);
+
+ assertTrue(data->buffer->current->memory[data->buffer->position] == 0x78,
+ "Wrong memory got %02X expected %02X",
+ data->buffer->current->memory[data->buffer->position], 0x78)
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * Set position to a good location that is not in the current block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent)
+{
+ // Write an array that will span 5 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, 4777);
+
+ assertTrue(data->buffer->position == 4777, "Wrong position set, got %zu expected %u", data->buffer->position, 4777);
+ assertTrue(_ccnxCodecNetworkBufferMemory_ContainsPosition(data->buffer->current, 4777), "Did not seek to right position");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ assertTrue(iov == vec->array, "Got wrong iovec array, got %p expected %p", (void *) iov, (void *) vec->array);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(ccnxCodecNetworkBufferIoVec_GetCount(vec) == 5, "iovcnt wrong got %d expected %d", ccnxCodecNetworkBufferIoVec_GetCount(vec), 5);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(vec) == arrayLength, "Wrong length got %zu expected %zu", ccnxCodecNetworkBufferIoVec_Length(vec), arrayLength);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+// =====================================================================
+
+LONGBOW_TEST_FIXTURE(SetLimit)
+{
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(SetLimit)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(SetLimit)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+typedef struct setlimit_s {
+ CCNxCodecNetworkBuffer *netbuff;
+ PARCBuffer *truth;
+} SetLimitData;
+
+/*
+ * In this test, SetLimit is called when we are at position 4036
+ *
+ * (always in ABSOLUTE bytes)
+ * position = 4077
+ * begin = 0 begin = 1536 begin = 3577 |
+ * | | | |
+ * +--------------------------+--------------------------+--------------------------+
+ * | block 0 | block 1 | block 2 |
+ * +--------------------------+--------------------------+--------------------------+
+ * | | | |
+ * capacity = 1536 capacity = 2048 | capacity = 2048
+ * limit = 1536 limit = 2041 limit = 500
+ * (always in RELATIVE bytes)
+ */
+static SetLimitData
+_allocateData(void)
+{
+ SetLimitData data;
+
+ data.netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+
+ size_t buffer1_length = 3577;
+ uint8_t buffer1[buffer1_length];
+ memset(buffer1, 0x11, buffer1_length);
+
+ ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer1_length, buffer1);
+ assertTrue(data.netbuff->position == buffer1_length, "Wrong position, expected %zu got %zu", buffer1_length, data.netbuff->position);
+
+ // we should be in 'block1' in the diagram
+ assertTrue(data.netbuff->current->limit == 2041, "wrong limit, expected %u got %zu", 2041, data.netbuff->current->limit);
+
+ // now allocate the second buffer to move to 'block 2'. this should freeze 'block 1' at 2000 bytes.
+
+ // now we need to write it at 8 bytes to get block 1 to freeze
+ uint64_t x = 0x1234567812345678ULL;
+
+ ccnxCodecNetworkBuffer_PutUint64(data.netbuff, x);
+ assertTrue(data.netbuff->position == 3585, "Wrong position, expected %u got %zu", 3585, data.netbuff->position);
+ assertTrue(data.netbuff->current->limit == 8, "wrong limit, expected %u got %zu", 8, data.netbuff->current->limit);
+
+ size_t buffer2_length = 492;
+ uint8_t buffer2[buffer2_length];
+ memset(buffer2, 0xaa, buffer2_length);
+
+ ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer2_length, buffer2);
+
+ assertTrue(data.netbuff->position == 4077, "Wrong position, expected %u got %zu", 4077, data.netbuff->current->limit);
+ assertTrue(data.netbuff->current->limit == 500, "wrong limit, expected %u got %zu", 500, data.netbuff->current->limit);
+
+ data.truth = parcBuffer_Allocate(buffer1_length + buffer2_length + 8);
+ parcBuffer_PutArray(data.truth, buffer1_length, buffer1);
+ parcBuffer_PutUint64(data.truth, x);
+ parcBuffer_PutArray(data.truth, buffer2_length, buffer2);
+ parcBuffer_Flip(data.truth);
+
+ return data;
+}
+
+static void
+_destroyData(SetLimitData data)
+{
+ ccnxCodecNetworkBuffer_Release(&data.netbuff);
+ parcBuffer_Release(&data.truth);
+}
+
+static void
+_runDataTest(size_t position)
+{
+ SetLimitData data = _allocateData();
+ ccnxCodecNetworkBuffer_SetPosition(data.netbuff, position);
+ parcBuffer_SetLimit(data.truth, position);
+
+ ccnxCodecNetworkBuffer_Finalize(data.netbuff);
+ PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(data.netbuff);
+ assertTrue(parcBuffer_Equals(data.truth, test), "wrong value")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(data.truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ _destroyData(data);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 4077
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail)
+{
+ _runDataTest(4077);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 4000, which
+ * is in the middle of 'block 2'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail)
+{
+ _runDataTest(4000);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 3577, which
+ * is in the start of 'block 2'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail)
+{
+ _runDataTest(3577);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 3576, which
+ * is the last byte of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid)
+{
+ _runDataTest(3576);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 2000, which
+ * is the middle of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid)
+{
+ _runDataTest(2000);
+}
+
+/*
+ * 1536 is 1st byte of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid)
+{
+ _runDataTest(1536);
+}
+
+/*
+ * Wipe it all out
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero)
+{
+ _runDataTest(0);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecNetworkBufferMemory_Allocate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _ccnxCodecNetworkBufferMemory_Allocate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ size_t desired = 2048;
+ CCNxCodecNetworkBufferMemory *memory = _ccnxCodecNetworkBufferMemory_Allocate(data->buffer, desired);
+ assertNotNull(memory, "Got null memory");
+ assertNull(memory->next, "memory->next is not null");
+ assertTrue(memory->begin == 0, "memory has wrong offset, got %zu expecting %u", memory->begin, 0);
+ assertTrue(memory->capacity == desired, "Wrong capacity, got %zu expecting %zu", memory->capacity, desired);
+
+ _ccnxCodecNetworkBufferMemory_Release(data->buffer, &memory);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NetworkBuffer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c
new file mode 100755
index 00000000..db835bb5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c
@@ -0,0 +1,808 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+
+LONGBOW_TEST_RUNNER(parc_Tlv)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Decoder);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Tlv)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ============================================
+
+LONGBOW_TEST_FIXTURE(Decoder)
+{
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Decoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Decoder)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * check for memory leaks on create/destroy
+ */
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ size_t after = parcMemory_Outstanding();
+ parcBuffer_Release(&buffer);
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ // we're calling this on byte 0, so the "length" will be 0x0001
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 2, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(length == 1, "Wrong length expected %u got %u", 1, length);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 2, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_PeekType(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 0,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 0, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+ assertTrue(length == 19, "Wrong length expected %u got %u", 19, length);
+
+ PARCBuffer *inner = ccnxCodecTlvDecoder_GetValue(outerDecoder, length);
+
+ // inner should now be empty
+ assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "outer decoder should be emtpy");
+
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_Create(inner);
+ parcBuffer_Release(&inner);
+
+ type = ccnxCodecTlvDecoder_GetType(innerDecoder);
+ length = ccnxCodecTlvDecoder_GetLength(innerDecoder);
+
+ assertTrue(type == 2, "Wrong type expected %u got %u", 2, type);
+ assertTrue(length == 5, "Wrong length expected %u got %u", 5, length);
+
+ PARCBuffer *hello = ccnxCodecTlvDecoder_GetValue(innerDecoder, length);
+
+ parcBuffer_Release(&hello);
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong)
+{
+ // Length is beyond end of buffer
+ uint8_t truthBytes[] = { 0x00, 0x02, 0x00, 0x99, 'h', 'e', 'l', 'l', 'o' };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, length);
+
+ assertNull(value, "Value should be null because of buffer underrun");
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, sizeof(truthBytes));
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was not empty when its should be empty");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertFalse(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was empty when its full");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, 8);
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxCodecTlvDecoder_Position(outerDecoder) == 8,
+ "Decoder reports wrong position, expected %u got %zu",
+ 8,
+ ccnxCodecTlvDecoder_Position(outerDecoder));
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True)
+{
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 5);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+
+ assertTrue(success,
+ "Decoder failed ensureRemaining check for 5 bytes when its a 19 byte buffer");
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False)
+{
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 24);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+
+ assertFalse(success,
+ "Decoder passed ensureRemaining check for 24 bytes when its a 19 byte buffer");
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF, "Incorrect value, expected 0x%X got 0x%X", 0xFF, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 4);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed a short buffer");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x99, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF01, "Incorrect value, expected 0x%X got 0x%X", 0xFF01, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x99, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF010203, "Incorrect value, expected 0x%X got 0x%X", 0xFF010203, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 7);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ uint64_t truth = 0xFF01020304050607ULL;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == truth, "Incorrect value, expected %#" PRIx64 " got %#" PRIx64, truth, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x01, 0x02, 0x03, 0x04 }, 4, 0, 4);
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType)
+{
+ // INNER TYPE IS WRONG
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xFF, 0xFF, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of incorrect TLV type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort)
+{
+ // OVERALL LENGTH TOO SHORT TO PARSE
+ // buffer only goes to here ---------------------------------!
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of input underrun");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong)
+{
+ // VALUE (4 bytes) SHORTER THAN LENGTH (0x99)
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x99, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of value underrun");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, length);
+ assertNotNull(innerDecoder, "Got a null decoder for a valid slice");
+ assertTrue(ccnxCodecTlvDecoder_Position(innerDecoder) == 0, "Wrong position, expected 0 got %zu", ccnxCodecTlvDecoder_Position(innerDecoder));
+ assertTrue(ccnxCodecTlvDecoder_EnsureRemaining(innerDecoder, 19), "Inner decoder does not have enough bytes in it");
+
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ (void) ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ // ask for too many bytes
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, 100);
+ assertNull(innerDecoder, "Got a decoder for an invalid slice");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ size_t advance = 3;
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder);
+ bool success = ccnxCodecTlvDecoder_Advance(decoder, advance);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder);
+
+ assertTrue(success, "Failed to advance decoder");
+ assertTrue(beforePosition + advance == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition + advance);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ size_t advance = 9;
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder);
+ bool success = ccnxCodecTlvDecoder_Advance(decoder, advance);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder);
+
+ assertFalse(success, "Should have returned false advancing beyond end of decoder");
+ assertTrue(beforePosition == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ // length 0 invalid
+ { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } },
+ { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} },
+ { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} },
+ { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} },
+ { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // length 9 invalid
+ { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, vectors[i].length, &value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid);
+ if (vectors[i].valid) {
+ assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value);
+ }
+ }
+}
+
+// ============================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c
new file mode 100755
index 00000000..0898077d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c
@@ -0,0 +1,874 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+
+LONGBOW_TEST_RUNNER(parc_Tlv)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Encoder);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Tlv)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==========================================
+
+LONGBOW_TEST_FIXTURE(Encoder)
+{
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Encoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Encoder)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ uint8_t mrTlvString[] = "mr tlv";
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ // sizeof -1 to account for null byte at end of string
+ ccnxCodecTlvEncoder_AppendArray(innerEncoder, 2, sizeof(helloString) - 1, helloString);
+ ccnxCodecTlvEncoder_AppendArray(innerEncoder, 3, sizeof(mrTlvString) - 1, mrTlvString);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(container, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ uint8_t mrTlvString[] = "mr tlv";
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ // sizeof -1 to account for null byte at end of string
+ ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 2, sizeof(helloString) - 1);
+ ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(helloString) - 1, helloString);
+ ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 3, sizeof(mrTlvString) - 1);
+ ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(mrTlvString) - 1, mrTlvString);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(container, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+
+/**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ uint8_t mrTlvString[] = "mr tlv";
+ PARCBuffer *mrTlv = parcBuffer_Wrap(mrTlvString, 6, 0, 6);
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 2, hello);
+ ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 3, mrTlv);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+ parcBuffer_Release(&hello);
+ parcBuffer_Release(&mrTlv);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container),
+ "buffers not equal\nexpected '%s'\ngot '%s'\n",
+ parcBuffer_ToString(truth),
+ parcBuffer_ToString(container)
+ );
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t trueLength = 2 + 2 + 5;
+ size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer)
+{
+ uint8_t truthString[] = { 0x00, 0x02, 0xF1, 0x07 };
+ PARCBuffer *truth = parcBuffer_Wrap(truthString, 4, 0, 4);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t trueLength = 2 + 2;
+ size_t length = ccnxCodecTlvEncoder_AppendContainer(encoder, 2, 0xF107);
+ assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffer is incorrect.");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+}
+
+/**
+ * Check for memory leaks and correct isInitialized state
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ // add a signer to make sure it is destroyed
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ // add an error to make sure its destroyed too
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/**
+ * Check for memory leaks
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ parcBuffer_Release(&test);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/*
+ * Do a long write, then backup the position.
+ * After Finalize, the Limit should have trimmed off the erased part.
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array);
+ ccnxCodecTlvEncoder_SetPosition(encoder, 3);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Remaining(test) == 3, "Wrong length, expected 3 got %zu", parcBuffer_Remaining(test));
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Do a long write, then backup the position.
+ * After Finalize, the Limit should have trimmed off the erased part.
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array);
+ ccnxCodecTlvEncoder_SetPosition(encoder, 3);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+
+ CCNxCodecNetworkBufferIoVec *iov = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(iov) == 3, "Wrong length, expected 3 got %zu", ccnxCodecNetworkBufferIoVec_Length(iov));
+
+ ccnxCodecNetworkBufferIoVec_Release(&iov);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/**
+ * Check for memory leaks and correct isInitialized state
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/**
+ * Make sure calling Initialized on an Initialized buffer does not leak
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ size_t position = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(length == position, "Position not right expected %zu got %zu", length, position);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+
+ size_t currentPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ // when I set the length of the first container, we should be positioned back to
+ // the current location.
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, 99);
+ size_t testPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(testPosition == currentPosition, "Position not right expected %zu got %zu", currentPosition, testPosition);
+
+ // and make sure the length was updated
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *output = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ parcBuffer_SetPosition(output, 2);
+ uint16_t testlength = parcBuffer_GetUint16(output);
+
+ assertTrue(testlength == 99, "Updated length wrong, expected %u got %u", 99, testlength);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+ parcBuffer_Release(&output);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint16(encoder, 0x1021, 0xFF01);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint32(encoder, 0x1022, 0xFF010203);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint64(encoder, 0x1023, 0xFF01020304050607ULL);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ { .value = 0, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0xFF } },
+ { .value = 0x0101, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0x01, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0xFF, 0x01} },
+ { .value = 0x010001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0x01, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0xFF, 0x00, 0x01} },
+ { .value = 0x01000000, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00} },
+ { .value = 0xFF002001, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 12, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ // only do the valid ones for the encode test
+ if (vectors[i].valid) {
+ PARCBuffer *truth = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ size_t length = ccnxCodecTlvEncoder_AppendVarInt(encoder, 0x1023, vectors[i].value);
+
+ assertTrue(length == vectors[i].length, "Wrong length index %d, got %zu expected %d", i, length, vectors[i].length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal index %d", i)
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ assertTrue(encoder->signatureEnd == 5, "Wrong end position, expected %u got %zu", 5, encoder->signatureEnd)
+ {
+ ccnxCodecNetworkBuffer_Display(encoder->buffer, 3);
+ }
+
+ assertTrue(encoder->signatureStartEndSet == END_SET, "Wrong flag, expected %d got %d", END_SET, encoder->signatureStartEndSet);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ assertTrue(encoder->signatureStart == 5, "Wrong start position, expected %u got %zu", 5, encoder->signatureStart)
+ {
+ ccnxCodecNetworkBuffer_Display(encoder->buffer, 3);
+ }
+
+ assertTrue(encoder->signatureStartEndSet == START_SET, "Wrong flag, expected %d got %d", START_SET, encoder->signatureStartEndSet);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ assertTrue(encoder->signatureStartEndSet == BOTH_SET, "Wrong flag, expected %d got %d", BOTH_SET, encoder->signatureStartEndSet);
+
+ PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ assertNotNull(sig, "Got null signature");
+
+ uint8_t truesig[] = { 0xA3, 0xAA, 0xC8, 0x4B };
+ PARCBuffer *truesigBuffer = parcBuffer_Rewind(parcBuffer_CreateFromArray(truesig, sizeof(truesig)));
+ PARCBuffer *test = parcSignature_GetSignature(sig);
+ assertTrue(parcBuffer_Equals(truesigBuffer, test), "wrong crc value")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truesigBuffer, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truesigBuffer);
+ parcSignature_Release(&sig);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ PARCSigner *test = ccnxCodecTlvEncoder_GetSigner(encoder);
+ assertTrue(test == signer, "Did not return the right signer, expected %p got %p", (void *) signer, (void *) test);
+ parcSigner_Release(&signer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_PutUint8(encoder, 1, 0xEE);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0xDD, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_PutUint16(encoder, 1, 0xEEDD);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ // position is now at 9 (2+2+5)
+
+ ccnxCodecTlvEncoder_SetPosition(encoder, 2);
+
+ size_t position = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(2 == position, "Position not right expected %u got %zu", 2, position);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+
+ // now try to set a second time
+ bool success = ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+
+ assertFalse(success, "Returned success when should have failed");
+ assertNotNull(encoder->error, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ bool success = ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ assertTrue(success, "Returned failure when should have succeeded");
+ assertNotNull(encoder->error, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ CCNxCodecError *test = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(test, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ ccnxCodecTlvEncoder_ClearError(encoder);
+ assertNull(encoder->error, "Encoder does not have a null error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_ClearError(encoder);
+ assertNull(encoder->error, "Encoder does not have a null error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+// ============================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecTlvEncoder_ComputeVarIntLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _ccnxCodecTlvEncoder_ComputeVarIntLength)
+{
+ struct test_vector {
+ uint64_t value;
+ int length;
+ } vectors[] = {
+ { .value = 0, .length = 1 },
+ { .value = 0xFF, .length = 1 },
+ { .value = 0x0101, .length = 2 },
+ { .value = 0xFF01, .length = 2 },
+ { .value = 0x010001, .length = 3 },
+ { .value = 0xFF0001, .length = 3 },
+ { .value = 0x01000000, .length = 4 },
+ { .value = 0xFF002001, .length = 4 },
+ { .value = 0x0100000000, .length = 5 },
+ { .value = 0xFF00002001, .length = 5 },
+ { .value = 0x010000000000, .length = 6 },
+ { .value = 0xFF0000002001, .length = 6 },
+ { .value = 0x01000000000000, .length = 7 },
+ { .value = 0xFF000000002001, .length = 7 },
+ { .value = 0xFF00200103040506ULL, .length = 8 },
+ // sentinal is length 0
+ { .value = 0, .length = 0 },
+ };
+
+ for (int i = 0; vectors[i].length != 0; i++) {
+ unsigned test = _ccnxCodecTlvEncoder_ComputeVarIntLength(vectors[i].value);
+ assertTrue(test == vectors[i].length, "Incorrect length index %d, expected %u got %u", i, vectors[i].length, test);
+ }
+}
+
+
+// ===================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c
new file mode 100644
index 00000000..2dfdfcb3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c
@@ -0,0 +1,447 @@
+/*
+ * 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.
+ */
+
+/**
+ * Does not do detailed tests of the decode -- those are tested in the individual schema_vX unit tests.
+ * These tests make sure that we (a) get a result when we expect to get a results, and (b) will spot-check
+ * the result, such as looking at the Name.
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "../ccnxCodec_TlvPacket.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h>
+
+LONGBOW_TEST_RUNNER(rta_TlvPacket)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_TlvPacket)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvPacket)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ parcBufferComposer_PutBuffer(composer, interestMessage);
+ parcBuffer_Release(&interestMessage);
+
+ // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message.
+ PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed");
+ parcBufferComposer_PutBuffer(composer, padding);
+ parcBuffer_Release(&padding);
+ PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Rewind(packetBuffer);
+
+ //PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict);
+ assertTrue(success, "Failed to decode good v1 interest");
+
+ CCNxName *name = ccnxInterest_GetName(dict);
+ assertNotNull(name, "Did not find a name in the decoded interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF)
+{
+ uint8_t encoded[] = {
+ 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict);
+ assertFalse(success, "Did not fail on decode of version 255 packet");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+typedef struct allocator_arg {
+ size_t maxallocation;
+} AllocatorArg;
+
+static size_t
+testAllocator(void *userarg, size_t bytes, void **output)
+{
+ AllocatorArg *arg = userarg;
+ if (bytes > arg->maxallocation) {
+ bytes = arg->maxallocation;
+ }
+
+ *output = parcMemory_Allocate(bytes);
+ assertNotNull(*output, "parcMemory_Allocate(%zu) returned NULL", bytes);
+ if (*output) {
+ return bytes;
+ }
+ return 0;
+}
+
+static void
+testDeallocator(void *userarg, void **memory)
+{
+ parcMemory_Deallocate((void **) memory);
+}
+
+const CCNxCodecNetworkBufferMemoryBlockFunctions TestMemoryBlock = {
+ .allocator = &testAllocator,
+ .deallocator = &testDeallocator
+};
+
+
+static void
+runIoVecTest(AllocatorArg maxalloc)
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&TestMemoryBlock, &maxalloc);
+
+ ccnxCodecNetworkBuffer_PutArray(netbuff,
+ sizeof(v1_interest_all_fields),
+ v1_interest_all_fields);
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *output = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ ccnxTlvDictionary_SetMessageType_Interest(output, CCNxTlvDictionary_SchemaVersion_V1);
+
+ bool success = ccnxCodecTlvPacket_IoVecDecode(vec, output);
+ assertTrue(success, "Failed to decode buffer in iovec format");
+
+ ccnxTlvDictionary_Release(&output);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer)
+{
+ AllocatorArg maxalloc = { .maxallocation = 2048 };
+ runIoVecTest(maxalloc);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer)
+{
+ // 32 bytes is needed for bookkeeping, so this means we'll have a 32-byte memory block
+ AllocatorArg maxalloc = { .maxallocation = 64 };
+ runIoVecTest(maxalloc);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/Antidisestablishmentarianism");
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, CCNxInterestDefault_HopLimit);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL);
+ assertNotNull(iovec, "Got null iovec on a good dictionary");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF)
+{
+ CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20);
+ ccnxTlvDictionary_SetMessageType_Interest(message, 0xFF);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL);
+ assertNull(iovec, "Should have gotten null result for schema version 255");
+ ccnxTlvDictionary_Release(&message);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ parcBufferComposer_PutBuffer(composer, interestMessage);
+ parcBuffer_Release(&interestMessage);
+
+ // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message.
+ PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed");
+ parcBufferComposer_PutBuffer(composer, padding);
+ parcBuffer_Release(&padding);
+ PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Rewind(packetBuffer);
+
+ CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer);
+ assertNotNull(dict, "Got null dictionary decoding good packet");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF)
+{
+ uint8_t encoded[] = {
+ 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer);
+ assertNull(dict, "Got non-null dictionary decoding version 255 packet");
+ parcBuffer_Release(&packetBuffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_WrapCString("payload");
+ CCNxContentObject *obj = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+
+ PARCBuffer *secretKey = parcBuffer_WrapCString("abcdefghijklmnopqrstuvwxyx");
+ PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey);
+
+ // should really scrub the memory
+ parcBuffer_Release(&secretKey);
+
+ // this was breaking the signature
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ const PARCCryptoHash *secretHash = parcKeyStore_GetVerifierKeyDigest(keyStore);
+ const PARCBuffer *keyid = parcCryptoHash_GetDigest(secretHash);
+ ccnxValidationHmacSha256_Set(obj, keyid);
+ parcCryptoHash_Release((PARCCryptoHash **) &secretHash);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(obj, signer);
+
+ ccnxCodecNetworkBufferIoVec_Display(iovec, 0);
+
+ int fd = open("/dev/null", O_WRONLY);
+ assertTrue(fd != -1, "Error opening /dev/null");
+
+ ssize_t written = writev(fd, ccnxCodecNetworkBufferIoVec_GetArray(iovec), ccnxCodecNetworkBufferIoVec_GetCount(iovec));
+ assertTrue(written != -1, "Error writting to /dev/null");
+ close(fd);
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ parcSigner_Release(&signer);
+ ccnxContentObject_Release(&obj);
+}
+
+static uint8_t testDataV1_Interest_AllFields[] = {
+ 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100
+ 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 82, // type = interest, length = 82
+ // ------------------------
+ 0x00, 0x00, 0x00, 8, // type = name, length = 8
+ 0x00, 0x02, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+ // ------------------------
+ 0x00, 0x02, 0x00, 16, // type = keyid restriction, length = 16
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ // ------------------------
+ 0x00, 0x03, 0x00, 32, // type = hash restriction, length = 32
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb,
+ 0xcc, 0xcd, 0xce, 0xcf,
+ // ------------------------
+ 0x00, 0x04, 0x00, 1, // Internest payload method (1 byte)
+ 0x00,
+ // ------------------------
+ 0x00, 0x01, 0x00, 5, // type = payload, length = 5
+ 0xD0, 0xD1, 0xD2, 0xD3,
+ 0xD4,
+};
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength)
+{
+ PARCBuffer *packet = parcBuffer_Wrap(testDataV1_Interest_AllFields, sizeof(testDataV1_Interest_AllFields), 0, sizeof(testDataV1_Interest_AllFields));
+ size_t packetLength = ccnxCodecTlvPacket_GetPacketLength(packet);
+ assertTrue(packetLength == sizeof(testDataV1_Interest_AllFields), "Wrong total message length, expected %zu got %zu", sizeof(testDataV1_Interest_AllFields), packetLength);
+ parcBuffer_Release(&packet);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength)
+{
+ assertTrue(ccnxCodecTlvPacket_MinimalHeaderLength() > 0, "ccnxCodecTlvPacket_MinimalHeaderLength failed");
+}
+
+// =================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Interest);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Control);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Unknown);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Error);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Interest)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNotNull(dict, "Error decoding good packet");
+
+ CCNxName *name = ccnxInterest_GetName(dict);
+ assertNotNull(name, "Null name in decoded Interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_ContentObject)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNotNull(dict, "Error decoding good packet");
+
+ CCNxName *name = ccnxContentObject_GetName(dict);
+ assertNotNull(name, "Null name in decoded Interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Control)
+{
+ testUnimplemented("V1 control not implemented yet");
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Unknown)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNull(dict, "Should have gotten NULL dictionary from unknown packet type");
+
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Error)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNull(dict, "Should have gotten NULL dictionary from unknown packet type");
+
+ parcBuffer_Release(&packetBuffer);
+}
+
+// =================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvPacket);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c
new file mode 100644
index 00000000..b8215822
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c
@@ -0,0 +1,496 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvUtilities.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+
+typedef struct test_data {
+ uint8_t *packet;
+ PARCBuffer *fixedHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t headerLength;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->packet = parcMemory_Allocate(8);
+ assertNotNull(data->packet, "parcMemory_Allocate(%u) returned NULL", 8);
+
+ // Make a V1 fixed header
+ memcpy(data->packet, &((uint8_t[]) {
+ 0x01, // version
+ 0x01, // packetType
+ 0x01, 0x02, // packetLength
+ 0x00, // hopLimit/hopCount
+ 0x00, // returnCode
+ 0x03, // flags
+ 0x04 // headerLength
+ }), 8);
+
+
+ data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8);
+ data->version = 1;
+ data->packetType = 1;
+ data->packetLength = 0x0102;
+ data->headerLength = 0x04;
+ data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader);
+ data->dictionary = ccnxTlvDictionary_Create(10, 10);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->fixedHeader);
+ parcMemory_Deallocate((void **) &(data->packet));
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_TlvUtilities)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_TlvUtilities)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvUtilities)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t type = 1;
+ uint32_t length = 8;
+
+ bool success = ccnxCodecTlvUtilities_PutAsBuffer(data->decoder, data->dictionary, type, length,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ assertTrue(success, "Failed to save buffer slice");
+
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 0x20, // 0x01 = CCNxCodecSchemaV1Types_HashType_SHA256
+ 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 *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+
+ uint16_t type = 0x01;
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 10);
+ bool success = ccnxCodecTlvUtilities_PutAsHash(decoder, dictionary, type, sizeof(encoded),
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ assertTrue(success, "Failed to save hash");
+
+ parcBuffer_Release(&tlvBuffer);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ // length 0 invalid
+ { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } },
+ { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} },
+ { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} },
+ { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} },
+ { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // length 9 invalid
+ { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+
+ uint64_t value;
+ bool success = ccnxCodecTlvUtilities_GetVarInt(buffer, vectors[i].length, &value);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid);
+ if (vectors[i].valid) {
+ assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value);
+ }
+ }
+}
+
+
+static bool
+_decodeSubContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return true;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer)
+{
+ uint8_t metadata[] = {
+ 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ 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(metadata, sizeof(metadata), 0, sizeof(metadata));
+
+ // now decode that snippit
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20);
+
+ uint16_t key = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ bool success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, dictionary, key, length, _decodeSubContainer);
+
+ assertTrue(success, "Failed to decode metadata container");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+
+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;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer)
+{
+ 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");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName)
+{
+ // A list of 2 TLV containers (types 0x000C and 0x000D)
+ uint8_t nameContainer[] = {
+ 0x00, 0x00, 0x00, 9, // type = name, length = 9
+ 0x00, 0x03, 0x00, 5, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(nameContainer, sizeof(nameContainer), 0, sizeof(nameContainer));
+
+ // 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:/3=hello"
+ bool success = ccnxCodecTlvUtilities_PutAsName(decoder, dictionary, tlvtype, tlvlength, 1);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success, "The Name failed to decode or some other error");
+
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=hello");
+ CCNxName *test = ccnxTlvDictionary_GetName(dictionary, 1);
+ assertTrue(ccnxName_Equals(truth, test), "Names not equal")
+ {
+ ccnxName_Display(test, 3);
+ ccnxName_Display(truth, 3);
+ ccnxName_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ }
+
+ ccnxName_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer)
+{
+ uint8_t array[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ PARCBuffer *truth[3];
+ truth[0] = parcBuffer_Wrap(array, sizeof(array), 0, 2);
+ truth[1] = parcBuffer_Wrap(array, sizeof(array), 2, 3);
+ truth[2] = parcBuffer_Wrap(array, sizeof(array), 3, 6);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list
+ int listkey = 1;
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 0, 2, listkey);
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 1, 1, listkey);
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 2, 3, listkey);
+
+ assertTrue(ccnxTlvDictionary_ListSize(dictionary, listkey) == 3,
+ "Wrong list size, got %zu expected %u",
+ ccnxTlvDictionary_ListSize(dictionary, listkey), 3);
+
+ // now make sure they are right
+ for (int i = 0; i < ccnxTlvDictionary_ListSize(dictionary, listkey); i++) {
+ PARCBuffer *test = ccnxTlvDictionary_ListGetByType(dictionary, listkey, i);
+ assertNotNull(test, "Failed to get index %d", i);
+
+ assertTrue(parcBuffer_Equals(truth[i], test), "Buffers not equal for index %d", i)
+ {
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth[i], 3);
+ }
+ }
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&truth[0]);
+ parcBuffer_Release(&truth[1]);
+ parcBuffer_Release(&truth[2]);
+ parcBuffer_Release(&buffer);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode)
+{
+// TODO: This test needs to be updated with V1 data.
+// See BugzID: 3919
+
+
+// uint8_t metadata[] = {
+// 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+// 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 *truth = parcBuffer_Wrap(metadata, sizeof(metadata), 0, sizeof(metadata));
+//
+// // now decode that snippit
+// CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truth);
+// CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20);
+// ccnxCodecTlvDecoder_Advance(decoder, 4);
+// ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, _ccnxCodecSchemaV0MetadataDecoder_DecodeType);
+//
+// // the dictionary should now be ready for encoding
+// ccnxCodecTlvDecoder_Destroy(&decoder);
+//
+// CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+// ssize_t length = ccnxCodecTlvUtilities_NestedEncode(encoder, dictionary, 0x000B, ccnxCodecSchemaV0MetadataEncoder_Encode);
+//
+// assertTrue(length == sizeof(metadata), "Wrong size, got %zu expected %zu", length, sizeof(metadata));
+//
+// ccnxCodecTlvEncoder_Finalize(encoder);
+// PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+// assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match")
+// {
+// parcBuffer_Display(test, 3);
+// parcBuffer_Display(truth, 3);
+// }
+//
+// ccnxCodecTlvEncoder_Destroy(&encoder);
+// ccnxTlvDictionary_Release(&dictionary);
+// parcBuffer_Release(&truth);
+// parcBuffer_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList)
+{
+ uint8_t truthArray[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02,
+ 0x00, 0x01, 0x00, 0x01, 0x03,
+ 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06 };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthArray, sizeof(truthArray), 0, sizeof(truthArray));
+
+ PARCBuffer *buffers[3];
+ buffers[0] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 4, 6);
+ buffers[1] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 10, 11);
+ buffers[2] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 15, 18);
+
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list
+ int listkey = 1;
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 2, buffers[2]);
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 1, buffers[1]);
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 0, buffers[0]);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvUtilities_EncodeCustomList(encoder, dictionary, listkey);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal")
+ {
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth, 3);
+ }
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&buffers[0]);
+ parcBuffer_Release(&buffers[1]);
+ parcBuffer_Release(&buffers[2]);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+// ====================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvUtilities);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes b/libccnx-common/ccnx/common/codec/test/test_random_bytes
new file mode 100644
index 00000000..33a80af5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig
new file mode 100644
index 00000000..9c395ce0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa.p12 b/libccnx-common/ccnx/common/codec/test/test_rsa.p12
new file mode 100644
index 00000000..471c4006
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_rsa.p12
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem
new file mode 100644
index 00000000..6c502b15
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8
+V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD
+6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB
+AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N
+zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj
+83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA
+r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3
+ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC
+3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6
+n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL
+U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ
+ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ
+PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ=
+-----END RSA PRIVATE KEY-----
diff --git a/libccnx-common/ccnx/common/codec/test/testrig_Compare.c b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c
new file mode 100755
index 00000000..3dc73a1c
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/**
+ * Utilities used by the Schema unit tests to compare buffers
+ *
+ */
+
+/**
+ * Compares an encoding buffer to linear memory
+ *
+ * Will assert if the memory does not compare. The encoding buffer will be finalized.
+ * Will assert if the encoder has an error.
+ *
+ * @param [in] encoder The encoding buffer to compare
+ * @param [in] length The length of linear memory
+ * @param [in] memory The "truth" memory to compare against
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+testCompareEncoderToLinearMemory(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t memory[length])
+{
+ assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ }
+
+ PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *buffer = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(buffer, truth), "buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+
+ printf("Got this\n");
+ parcBuffer_Display(buffer, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&buffer);
+}
+
+/**
+ * Compares an encoding buffer to a PARCBuffer
+ *
+ * Will assert if the memory does not compare. The encoding buffer will be finalized.
+ * Will assert if the encoder has an error.
+ *
+ * @param [in] encoder The encoding buffer to compare
+ * @param [in] buffer The buffer to compare to, must be setup to be read (i.e. flipped)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+testCompareEncoderToBuffer(CCNxCodecTlvEncoder *encoder, PARCBuffer *buffer)
+{
+ assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ }
+
+
+ uint8_t *linearMemory = parcByteArray_Array(parcBuffer_Array(buffer));
+ size_t offset = parcBuffer_ArrayOffset(buffer) + parcBuffer_Position(buffer);
+ size_t length = parcBuffer_Remaining(buffer);
+
+ testCompareEncoderToLinearMemory(encoder, length, linearMemory + offset);
+}
+
diff --git a/libccnx-common/ccnx/common/codec/testdata/testdata_common.h b/libccnx-common/ccnx/common/codec/testdata/testdata_common.h
new file mode 100644
index 00000000..ac1d0b8e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/testdata/testdata_common.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * testdata_common.h
+ * TransportRTA
+ */
+
+#ifndef TransportRTA_testdata_common_h
+#define TransportRTA_testdata_common_h
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+typedef struct tlv_extent {
+ uint16_t offset;
+ uint16_t length;
+} TlvExtent;
+
+// Equal to { 0xFFFF, 0xFFFF }
+extern const TlvExtent TlvExtentNotFound;
+
+/**
+ * Determine if two TlvExtent instances are equal.
+ *
+ * The following equivalence relations on non-null `TlvExtent` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `TlvExtent_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `tlvExtent_Equals(x, y)` must return true if and only if
+ * `tlvExtent_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `tlvExtent_Equals(x, y)` returns true and
+ * `tlvExtent_Equals(y, z)` returns true,
+ * then `tlvExtent_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `tlvExtent_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `tlvExtent_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `TlvExtent` instance.
+ * @param b A pointer to a `TlvExtent` instance.
+ * @return true if the two `TlvExtent` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * TlvExtent *a = tlvExtent_Create();
+ * TlvExtent *b = tlvExtent_Create();
+ *
+ * if (tlvExtent_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool tlvExtent_Equals(const TlvExtent *a, const TlvExtent *b);
+
+#define TRUTHTABLENAME(NAME) NAME ## _truthTableEntries
+
+// easy way to generate table entries, so long as you use the standard naming
+// convention for the the TruthTableEntry array
+#define TABLEENTRY(NAME, ERROR) { .testname = #NAME, .packet = NAME, .length = sizeof(NAME), .expectedError = ERROR, .entry = TRUTHTABLENAME(NAME) }
+
+typedef struct testrig_truth_table_entry {
+ bool wellKnownType;
+
+ // is the wellKnownType in the body manifest? or the header?
+ bool bodyManifest;
+
+ // if its a well known type, this is the manifest array index
+ // otherwise, its the unknown type value
+ int indexOrKey;
+
+ TlvExtent extent;
+} TruthTableEntry;
+
+
+typedef struct testrig_truth_table {
+ const char *testname;
+ uint8_t *packet;
+ size_t length;
+
+ CCNxCodecErrorCodes expectedError;
+
+ // the array is terminated by a T_INVALID value
+ // for "arrayIndexOrTypeKey"
+ TruthTableEntry *entry;
+} TruthTable;
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h b/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h
new file mode 100755
index 00000000..ddd8df7d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is from the version 0 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_tlv_Schema_h
+#define Libccnx_tlv_Schema_h
+
+#define T_INVALID 0xFFFF
+
+// not an actual type, but a virtual group
+#define T_VIRTUAL 0xFFFE
+#endif // Libccnx_tlv_Schema_h