From d18ae43123fcd7604d1c36a1ec8450dbe6071824 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 23 Feb 2017 20:44:26 +0100 Subject: Initial commit: ccnxlibs. Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0 Signed-off-by: Luca Muscariello --- .../schema_v1/ccnxCodecSchemaV1_PacketDecoder.c | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c (limited to 'libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c') 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 +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +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; +} -- cgit 1.2.3-korg