aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c')
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c353
1 files changed, 353 insertions, 0 deletions
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;
+}