summaryrefslogtreecommitdiffstats
path: root/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c')
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c484
1 files changed, 484 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c
new file mode 100644
index 00000000..daf851c7
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c
@@ -0,0 +1,484 @@
+/*
+ * 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 <fcntl.h>
+#include <sys/stat.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+#include <ccnx/common/internal/ccnx_WireFormatFacadeV1.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec(const CCNxCodecNetworkBufferIoVec *vec)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, vec);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestReturnPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromContentObjectPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromControlPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxCodecSchemaV1InterestHeader *
+_getWireFormatFixedHeader(CCNxTlvDictionary *dictionary)
+{
+ // Currently there is only one of either a PARCBuffer or an IoVec ...
+
+ CCNxCodecSchemaV1InterestHeader *header = NULL;
+
+ // Update attached iovec
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(dictionary);
+ if (iovec) {
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(iovec) >= sizeof(CCNxCodecSchemaV1InterestHeader),
+ "IoVector smaller than required for message header");
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+ assertTrue(iov[0].iov_len >= sizeof(CCNxCodecSchemaV1InterestHeader),
+ "Header not contained in first element of io vector");
+ header = iov[0].iov_base;
+ } else {
+ // Update attached buffer
+ PARCBuffer *wireFormatBuffer = ccnxWireFormatMessage_GetWireFormatBuffer(dictionary);
+ if (wireFormatBuffer) {
+ header = parcBuffer_Overlay(wireFormatBuffer, 0);
+ }
+ }
+
+ return header;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetHopLimit(CCNxTlvDictionary *dictionary, uint32_t hopLimit)
+{
+ bool result = false;
+
+ CCNxCodecSchemaV1InterestHeader *header = _getWireFormatFixedHeader(dictionary);
+ if (header != NULL) {
+ header->hopLimit = hopLimit;
+ result = true;
+ }
+ return result;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_ConvertInterestToInterestReturn(CCNxTlvDictionary *dictionary, uint8_t code)
+{
+ bool result = false;
+
+ CCNxCodecSchemaV1InterestHeader *header = _getWireFormatFixedHeader(dictionary);
+ if (header != NULL) {
+ header->returnCode = code;
+ header->packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn;
+ result = true;
+ }
+ return result;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_CreateFromV1(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = NULL;
+ uint8_t packetType = parcBuffer_GetAtIndex(wireFormat, 1);
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ dictionary = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_Control:
+ dictionary = _ccnxWireFormatFacadeV1_FromControlPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ dictionary = _ccnxWireFormatFacadeV1_FromInterestPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ dictionary = _ccnxWireFormatFacadeV1_FromInterestReturnPacketType(wireFormat);
+ break;
+ default:
+ // will return NULL
+ break;
+ }
+ return dictionary;
+}
+
+static PARCBuffer *
+_ccnxWireFormatFacadeV1_GetWireFormatBuffer(const CCNxTlvDictionary *dictionary)
+{
+ PARCBuffer *wireFormat = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat);
+ return wireFormat;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_PutWireFormatBuffer(CCNxTlvDictionary *dictionary, PARCBuffer *wireFormat)
+{
+ bool success = ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return success;
+}
+
+static CCNxCodecNetworkBufferIoVec *
+_ccnxWireFormatFacadeV1_GetIoVec(const CCNxTlvDictionary *dictionary)
+{
+ CCNxCodecNetworkBufferIoVec *vec = ccnxTlvDictionary_GetIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat);
+ return vec;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_PutIoVec(CCNxTlvDictionary *dictionary, CCNxCodecNetworkBufferIoVec *vec)
+{
+ bool success = ccnxTlvDictionary_PutIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, vec);
+ return success;
+}
+
+static void
+_ccnxWireFormatFacadeV1_WriteToFile(const CCNxTlvDictionary *dictionary, const char *filename)
+{
+ int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
+ PARCFileOutputStream *fos = parcFileOutputStream_Create(fd);
+
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ parcFileOutputStream_Write(fos, wireFormat);
+ parcBuffer_Rewind(wireFormat);
+ }
+
+ // this will close the file descriptor
+ parcFileOutputStream_Release(&fos);
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetProtectedRegionStart(CCNxTlvDictionary *dictionary, size_t startPosition)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(startPosition <= UINT16_MAX, "Start position beyond UINT16_MAX: %zu", startPosition);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart,
+ startPosition);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetProtectedRegionLength(CCNxTlvDictionary *dictionary, size_t length)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(length <= UINT16_MAX, "Length position beyond UINT16_MAX: %zu", length);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength,
+ length);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetContentObjectHashRegionStart(CCNxTlvDictionary *dictionary, size_t startPosition)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(startPosition <= UINT16_MAX, "Start position beyond UINT16_MAX: %zu", startPosition);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart,
+ startPosition);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetContentObjectHashRegionLength(CCNxTlvDictionary *dictionary, size_t length)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(length <= UINT16_MAX, "Length position beyond UINT16_MAX: %zu", length);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength,
+ length);
+ return success;
+}
+
+
+/*
+ * Compute the hash over the specified region. This is a static function, so we know the caller
+ * has verified all the parameters before giving them to us.
+ * The caller must also verify that (start + length <= totalLength).
+ *
+ * As we walk through the iovecs, the variables will look like this
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^ ^
+ * | | | |
+ * | start | end
+ * iovStart iovEnd
+ * |-------|---|
+ * offset
+ * remaining
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^
+ * | | |
+ * start | end
+ * iovStart iovEnd
+ * |-----------|
+ * offset (0)
+ * remaining (iov_len)
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^
+ * | |
+ * start end
+ * iovStart iovEnd
+ * |------|
+ * offset (0)
+ * remaining (end-start)
+ *
+ */
+static PARCCryptoHash *
+_hashProtectedRegionIoVec(CCNxCodecNetworkBufferIoVec *vec, PARCCryptoHasher *hasher, size_t start, size_t length)
+{
+ int failure = parcCryptoHasher_Init(hasher);
+ assertFalse(failure, "Error initializing the hasher");
+
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ int iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+
+ // iovStart is the beginning position of the current iovec
+ size_t iovStart = 0;
+ size_t end = start + length;
+
+ // Once iovStart is past end, we no longer need to loop, we're done
+ for (int i = 0; i < iovcnt && iovStart < end; i++) {
+ size_t iovEnd = iovStart + iov[i].iov_len;
+ iovEnd = (iovEnd > end) ? end : iovEnd;
+
+ // is "start" contained in this iovec?
+ if (iovStart <= start && start < iovEnd) {
+ size_t offset = start - iovStart;
+ size_t remaining = iovEnd - start;
+
+ failure = parcCryptoHasher_UpdateBytes(hasher, (const void *) ((uint8_t *) iov[i].iov_base + offset), remaining);
+ assertFalse(failure, "Error updating hasher iovec %d offset %zu remaining %zu", i, offset, remaining)
+ {
+ ccnxCodecNetworkBufferIoVec_Display(vec, 3);
+ }
+
+ // keep moving start to the next iovec
+ start += remaining;
+ }
+
+ iovStart += iov[i].iov_len;
+ }
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ return hash;
+}
+
+
+/*
+ * Compute the hash over the specified region. This is a static function, so we know the caller
+ * has verified all the parameters before giving them to us.
+ * The caller must also verify that (start + length <= parcBuffer_Limit).
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * PARCBuffer
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^ ^
+ * | | | |
+ * 0 start end Limit
+ */
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_ComputeBufferHash(PARCBuffer *wireFormat, PARCCryptoHasher *hasher, size_t start, size_t length)
+{
+ int failure = parcCryptoHasher_Init(hasher);
+ assertTrue(failure == 0, "Error initializing the hasher");
+
+ parcBuffer_SetPosition(wireFormat, start);
+ uint8_t *overlay = parcBuffer_Overlay(wireFormat, 0);
+
+ failure = parcCryptoHasher_UpdateBytes(hasher, overlay, length);
+ assertTrue(failure == 0, "Error updating hasher start %zu length %zu", start, length)
+ {
+ parcBuffer_Display(wireFormat, 3);
+ }
+
+ parcBuffer_Rewind(wireFormat);
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ return hash;
+}
+
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_HashProtectedRegion(const CCNxTlvDictionary *dictionary, PARCCryptoHasher *hasher)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(hasher, "Parameter hasher must be non-null");
+
+ PARCCryptoHash *hash = NULL;
+
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart)) {
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength)) {
+ size_t startPosition = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart);
+ size_t length = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength);
+
+ CCNxCodecNetworkBufferIoVec *vec = _ccnxWireFormatFacadeV1_GetIoVec(dictionary);
+ if (vec) {
+ size_t totalLength = ccnxCodecNetworkBufferIoVec_Length(vec);
+ if (startPosition + length <= totalLength) {
+ hash = _hashProtectedRegionIoVec(vec, hasher, startPosition, length);
+ }
+ } else {
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ size_t totalLength = parcBuffer_Remaining(wireFormat);
+ if (startPosition + length <= totalLength) {
+ hash = _ccnxWireFormatFacadeV1_ComputeBufferHash(wireFormat, hasher, startPosition, length);
+ }
+ }
+ }
+ }
+ }
+
+ return hash;
+}
+
+
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_ComputeContentObjectHash(CCNxTlvDictionary *dictionary)
+{
+ // This assumes the dictionary has been passed through something like the V1 packet decoder,
+ // (e.g. ccnxCodecSchemaV1PacketDecoder_Decode) and has had the protected region extents set.
+ // This will be the case for Athena. Metis has its own TLV parsing.
+
+ assertTrue(ccnxTlvDictionary_IsContentObject(dictionary) || ccnxTlvDictionary_IsManifest(dictionary), "Message must be a ContentObject or Manifest");
+
+ PARCCryptoHash *result = NULL;
+
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart)
+ && ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength)) {
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ size_t startPosition = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart);
+ size_t length = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength);
+
+ CCNxCodecNetworkBufferIoVec *vec = _ccnxWireFormatFacadeV1_GetIoVec(dictionary);
+ if (vec) {
+ size_t totalLength = ccnxCodecNetworkBufferIoVec_Length(vec);
+ if (startPosition + length <= totalLength) {
+ result = _hashProtectedRegionIoVec(vec, hasher, startPosition, length);
+ }
+ } else {
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ size_t totalLength = parcBuffer_Remaining(wireFormat);
+ if (startPosition + length <= totalLength) {
+ result = _ccnxWireFormatFacadeV1_ComputeBufferHash(wireFormat, hasher, startPosition, length);
+ }
+ }
+ }
+ parcCryptoHasher_Release(&hasher);
+ }
+
+ return result; // Could be NULL
+}
+
+
+/**
+ * `CCNxWireFormatFacadeV1_Implementation` is the structure containing the pointers to the
+ * V1 schema WireFormatMessage implementation.
+ */
+CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation = {
+ .description = "CCNxWireFormatFacadeV1_Implementation",
+
+ .create = &_ccnxWireFormatFacadeV1_CreateFromV1,
+
+ .fromInterestPacketType = &_ccnxWireFormatFacadeV1_FromInterestPacketType,
+
+ .fromInterestPacketTypeIoVec = &_ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec,
+
+ .fromContentObjectPacketType = &_ccnxWireFormatFacadeV1_FromContentObjectPacketType,
+
+ .fromControlPacketType = &_ccnxWireFormatFacadeV1_FromControlPacketType,
+
+ .getWireFormatBuffer = &_ccnxWireFormatFacadeV1_GetWireFormatBuffer,
+
+ .getIoVec = &_ccnxWireFormatFacadeV1_GetIoVec,
+
+ .putWireFormatBuffer = &_ccnxWireFormatFacadeV1_PutWireFormatBuffer,
+
+ .putIoVec = &_ccnxWireFormatFacadeV1_PutIoVec,
+
+ .writeToFile = &_ccnxWireFormatFacadeV1_WriteToFile,
+
+ .setProtectedRegionStart = &_ccnxWireFormatFacadeV1_SetProtectedRegionStart,
+
+ .setProtectedRegionLength = &_ccnxWireFormatFacadeV1_SetProtectedRegionLength,
+
+ .hashProtectedRegion = &_ccnxWireFormatFacadeV1_HashProtectedRegion,
+
+ .setContentObjectHashRegionStart = &_ccnxWireFormatFacadeV1_SetContentObjectHashRegionStart,
+
+ .setContentObjectHashRegionLength = &_ccnxWireFormatFacadeV1_SetContentObjectHashRegionLength,
+
+ .computeContentObjectHash = &_ccnxWireFormatFacadeV1_ComputeContentObjectHash,
+
+ .setHopLimit = &_ccnxWireFormatFacadeV1_SetHopLimit,
+
+ .convertInterestToInterestReturn = &_ccnxWireFormatFacadeV1_ConvertInterestToInterestReturn,
+};