diff options
Diffstat (limited to 'libccnx-common/ccnx/common/internal')
48 files changed, 9564 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c new file mode 100755 index 00000000..5af1b5ca --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c @@ -0,0 +1,60 @@ +/* + * 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 <unistd.h> + +#include <LongBow/runtime.h> + +#include <ccnx/common/internal/ccnx_ChunkingFacadeV1.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +static void +_assertInvariants(const CCNxTlvDictionary *dictionary) +{ + assertNotNull(dictionary, "Parameter contentObjectDictionary must be non-null"); + trapIllegalValueIf(ccnxTlvDictionary_GetSchemaVersion(dictionary) != CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(dictionary)); +} + +bool +ccnxChunkingFacadeV1_HasEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary) +{ + _assertInvariants(contentObjectDictionary); + return ccnxTlvDictionary_IsValueInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); +} + +uint64_t +ccnxChunkingFacadeV1_GetEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary) +{ + _assertInvariants(contentObjectDictionary); + return ccnxTlvDictionary_GetInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); +} + +bool +ccnxChunkingFacadeV1_SetEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary, uint64_t endChunkNumber) +{ + _assertInvariants(contentObjectDictionary); + trapIllegalValueIf(!ccnxTlvDictionary_IsContentObject(contentObjectDictionary), "Dictionary is not a ContentObject"); + return ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber); +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h new file mode 100755 index 00000000..a4d2010c --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h @@ -0,0 +1,103 @@ +/* + * 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 ccnx_ChunkingFacade.h + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ + +#ifndef libccnx_ccnx_ChunkingFacadeV1_h +#define libccnx_ccnx_ChunkingFacadeV1_h + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> + +/** + * Determines if an EndChunkNumber exists in the metadata + * + * Compatible with V0 and V1 schemas. + * + * @param [in] contentObjectDictionary A dictionary to check + * + * @return false There is no EndChunkNumber specified or the dictinoary is not a ContentObject + * @return true There is an EndChunkNumber specified + * + * Example: + * @code + * static PARCElasticBuffer * + * _ccnxContentObjectFacade_CreateFinalBlockId(const CCNxTlvDictionary *contentObjectDictionary) + * { + * if (ccnxChunkingFacade_HasEndChunkNumber(contentObjectDictionary)) { + * uint64_t endChunkNumber = ccnxChunkingFacade_GetEndChunkNumber(contentObjectDictionary); + * PARCElasticBuffer *fbid = _ccnxContentObjectFacade_EncodeFinalBlockId(endChunkNumber); + * return fbid; + * } + * return NULL; + * } + * @endcode + */ +bool ccnxChunkingFacadeV1_HasEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary); + +/** + * Retrieves the end chunk number + * + * Retieves the end chunk number as an unsigned 64-bit integer. + * This function will trapIllegalValue if there is not an EndChunkNumber present. + * The EndChunkNumber is the chunk number of the last Content Object in a chunked series. + * + * @param [in] contentObjectDictionary A dictionary to check + * + * @return number The ending chunk number + * + * Example: + * @code + * static PARCElasticBuffer * + * _ccnxContentObjectFacade_CreateFinalBlockId(const CCNxTlvDictionary *contentObjectDictionary) + * { + * if (ccnxChunkingFacade_HasEndChunkNumber(contentObjectDictionary)) { + * uint64_t endChunkNumber = ccnxChunkingFacade_GetEndChunkNumber(contentObjectDictionary); + * PARCElasticBuffer *fbid = _ccnxContentObjectFacade_EncodeFinalBlockId(endChunkNumber); + * return fbid; + * } + * return NULL; + * } + * @endcode + */ +uint64_t ccnxChunkingFacadeV1_GetEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary); + +/** + * Sets the EndChunkNumber of a ContentObject + * + * The dictionary must be a ContentObject, otherwise this function will trapIllegalValue. + * If an EndChunkNumber already exits, will not update but return false. + * + * @param [in] contentObjectDictionary A dictionary to check + * @param [in] endChunkNumber The ending chunk number + * + * @return true The value was set in the dictionary + * @return false A failure (likely value already set) + * + * Example: + * @code + * { + * CCNxTlvDictionary *obj = ccnxContentObjectFacade_Create(...); + * ccnxChunkingFacade_SetEndChunkNumber(obj, 74); + * } + * @endcode + */ +bool ccnxChunkingFacadeV1_SetEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary, uint64_t endChunkNumber); +#endif // libccnx_ccnx_ChunkingFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c new file mode 100644 index 00000000..1ca0c5af --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c @@ -0,0 +1,294 @@ +/* + * 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/security/parc_SigningAlgorithm.h> + +#include <ccnx/common/internal/ccnx_ContentObjectFacadeV1.h> +#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h> +#include <ccnx/common/internal/ccnx_ChunkingFacadeV1.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h> + +static void +_assertInvariants(const CCNxTlvDictionary *contentObjectDictionary) +{ + assertNotNull(contentObjectDictionary, "Dictionary is null"); + assertTrue(ccnxTlvDictionary_IsContentObject(contentObjectDictionary), "Dictionary is not a content object"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(contentObjectDictionary) == CCNxTlvDictionary_SchemaVersion_V1, + "Dictionary is wrong schema version, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(contentObjectDictionary), CCNxTlvDictionary_SchemaVersion_V1); +} + +// ========================= +// Creation + +static CCNxTlvDictionary * +_ccnxContentObjectFacadeV1_CreateWithNameAndPayload(const CCNxName *name, // required + const CCNxPayloadType payloadType, // required + const PARCBuffer *payload) // may be null +{ + assertNotNull(name, "Parameter name must be non-null"); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + if (dictionary) { + ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + if (payloadType != CCNxPayloadType_DATA) { + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType); + } + + if (payload) { + ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + } + } else { + trapOutOfMemory("Could not allocate ContentObject"); + } + + return dictionary; +} + +static CCNxTlvDictionary * +_ccnxContentObjectFacadeV1_CreateWithPayload(const CCNxPayloadType payloadType, // required + const PARCBuffer *payload) // may be null +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + if (dictionary) { + if (payloadType != CCNxPayloadType_DATA) { + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType); + } + + if (payload) { + ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + } + } else { + trapOutOfMemory("Could not allocate ContentObject"); + } + + return dictionary; +} + +// ========================= +// Getters + +static CCNxName * +_ccnxContentObjectFacadeV1_GetName(const CCNxTlvDictionary *contentObjectDictionary) +{ + _assertInvariants(contentObjectDictionary); + return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); +} + +static bool +_ccnxContentObjectFacadeV1_HasExpiryTime(const CCNxTlvDictionary *packetDictionary) +{ + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) { + return true; + } + return false; +} + +static uint64_t +_ccnxContentObjectFacadeV1_GetExpiryTime(const CCNxTlvDictionary *packetDictionary) +{ + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) { + return ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + } + trapUnexpectedState("The dictionary does not contain an Expiry Time"); +} + +static bool +_ccnxContentObjectFacadeV1_HasPathLabel(const CCNxTlvDictionary *packetDictionary) +{ + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) { + return true; + } + return false; +} + + +static uint64_t +_ccnxContentObjectFacadeV1_GetPathLabel(const CCNxTlvDictionary *packetDictionary) +{ + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) { + return ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel); + } + trapUnexpectedState("The dictionary does not contain a Path Label"); +} + +static PARCBuffer * +_ccnxContentObjectFacadeV1_GetPayload(const CCNxTlvDictionary *contentObjectDictionary) +{ + _assertInvariants(contentObjectDictionary); + return ccnxTlvDictionary_GetBuffer(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); +} + +static CCNxPayloadType +_ccnxContentObjectFacadeV1_GetPayloadType(const CCNxTlvDictionary *contentObjectDictionary) +{ + CCNxPayloadType result = CCNxPayloadType_DATA; + + _assertInvariants(contentObjectDictionary); + if (ccnxTlvDictionary_IsValueInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) { + result = (CCNxPayloadType) ccnxTlvDictionary_GetInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE); + } + + return result; +} + +// ========================= +// Setters + +static bool +_ccnxContentObjectFacadeV1_SetSignature(CCNxTlvDictionary *contentObject, const PARCBuffer *keyId, + const PARCSignature *signature, const CCNxKeyLocator *keyLocator) +{ + bool result = false; + + CCNxTlvDictionary *contentObjectDictionary = (CCNxTlvDictionary *) contentObject; + + if (parcSignature_GetSigningAlgorithm(signature) == PARCSigningAlgorithm_RSA + && parcSignature_GetHashType(signature) == PARCCryptoHashType_SHA256) { + ccnxValidationRsaSha256_Set(contentObjectDictionary, keyId, keyLocator); + } else if (parcSignature_GetSigningAlgorithm(signature) == PARCSigningAlgorithm_HMAC + && parcSignature_GetHashType(signature) == PARCCryptoHashType_SHA256) { + ccnxValidationHmacSha256_Set(contentObjectDictionary, keyId); + } else { + trapNotImplemented("Have not implemented the signature parameters"); + } + + PARCBuffer *sigbits = parcSignature_GetSignature(signature); + + result = ccnxValidationFacadeV1_SetPayload(contentObjectDictionary, sigbits); + + return result; +} + +static PARCBuffer * +_ccnxContentObjectFacadeV1_GetKeyId(const CCNxTlvDictionary *contentObject) +{ + return ccnxValidationFacadeV1_GetKeyId(contentObject); +} + +static bool +_ccnxContentObjectFacadeV1_SetExpiryTime(CCNxTlvDictionary *contentObjectDictionary, uint64_t expiryTime) +{ + bool success = ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiryTime); + trapUnexpectedStateIf(!success, "Could not set integer in dictionary"); + return success; +} + +static bool +_ccnxContentObjectFacadeV1_SetPathLabel(CCNxTlvDictionary *contentObjectDictionary, uint64_t pathLabel) +{ + bool success = ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel, pathLabel); + trapUnexpectedStateIf(!success, "Could not set integer in dictionary (path label)"); + return success; +} + +static bool +_ccnxContentObjectFacadeV1_SetPayload(CCNxTlvDictionary *contentObjectDictionary, CCNxPayloadType payloadType, const PARCBuffer *payload) +{ + bool result = false; + + if (payload != NULL) { + PARCBuffer *originalPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObjectDictionary); + + result = ccnxTlvDictionary_PutBuffer(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + + if (result) { + if (_ccnxContentObjectFacadeV1_GetPayloadType(contentObjectDictionary) != payloadType) { + ccnxTlvDictionary_PutInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType); + } + + if (originalPayload != NULL) { + parcBuffer_Release(&originalPayload); + } + } + } + + return result; +} + +// ========================= +// Miscellaneous functions + +static bool +_ccnxContentObjectFacadeV1_Equals(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB) +{ + return ccnxTlvDictionary_Equals(objectA, objectB); +} + +static char * +_ccnxContentObjectFacadeV1_ToString(const CCNxTlvDictionary *contentObjectDictionary) +{ + trapNotImplemented("_ccnxContentObjectFacadeV1_ToString(): not yet implemented"); +} + +static void +_ccnxContentObjectFacadeV1_Display(const CCNxTlvDictionary *contentObjectDictionary, size_t indentation) +{ + _assertInvariants(contentObjectDictionary); + ccnxTlvDictionary_Display(contentObjectDictionary, (unsigned) indentation); +} + +/** + * `CCNxContentObjectFacadeV1_Implementation` is the structure containing the pointers to the + * V1 schema ContentObject implementation. + */ +CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation = { + .description = "CCNxContentObjectFacadeV1_Implementation", + + .createWithNameAndPayload = &_ccnxContentObjectFacadeV1_CreateWithNameAndPayload, + .createWithPayload = &_ccnxContentObjectFacadeV1_CreateWithPayload, + + .setSignature = &_ccnxContentObjectFacadeV1_SetSignature, + .getKeyId = &_ccnxContentObjectFacadeV1_GetKeyId, + + .getName = &_ccnxContentObjectFacadeV1_GetName, + .getPayload = &_ccnxContentObjectFacadeV1_GetPayload, + .setPayload = &_ccnxContentObjectFacadeV1_SetPayload, + .getPayloadType = &_ccnxContentObjectFacadeV1_GetPayloadType, + + .getFinalChunkNumber = &ccnxChunkingFacadeV1_GetEndChunkNumber, + .setFinalChunkNumber = &ccnxChunkingFacadeV1_SetEndChunkNumber, + .hasFinalChunkNumber = &ccnxChunkingFacadeV1_HasEndChunkNumber, + + .getExpiryTime = &_ccnxContentObjectFacadeV1_GetExpiryTime, + .setExpiryTime = &_ccnxContentObjectFacadeV1_SetExpiryTime, + .hasExpiryTime = &_ccnxContentObjectFacadeV1_HasExpiryTime, + + .getPathLabel = &_ccnxContentObjectFacadeV1_GetPathLabel, + .setPathLabel = &_ccnxContentObjectFacadeV1_SetPathLabel, + .hasPathLabel = &_ccnxContentObjectFacadeV1_HasPathLabel, + + .toString = &_ccnxContentObjectFacadeV1_ToString, + .display = &_ccnxContentObjectFacadeV1_Display, + .equals = &_ccnxContentObjectFacadeV1_Equals, + + .assertValid = &_assertInvariants, +}; diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h new file mode 100755 index 00000000..d95c56b3 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.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. + */ + +/** + * @file ccnx_ContentObjectFacade.h + * @ingroup ContentObject + * @brief This facade is used to access fields within an RTA-encoded content object. + * + * Content objects are encoded and transmitted through the transport stack before being sent over the wire. + * This facade acts an interface to this transport-specific encoding of the content object. It enables + * the user to directly access fields within the content object without having any knowledge about the + * particular schema-specific encoding. + * + */ +#ifndef libccnx_ccnx_ContentObjectFacadeV1_h +#define libccnx_ccnx_ContentObjectFacadeV1_h + +#include <ccnx/common/internal/ccnx_ContentObjectInterface.h> + +extern CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation; + +#endif // libccnx_ccnx_ContentObjectFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c new file mode 100755 index 00000000..ac33c2ab --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c @@ -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. + */ + +/** + */ + +#include <config.h> + +#include <LongBow/runtime.h> + +#include <ccnx/common/internal/ccnx_ContentObjectInterface.h> + + +CCNxContentObjectInterface * +ccnxContentObjectInterface_GetInterface(const CCNxTlvDictionary *dictionary) +{ + assertTrue(ccnxTlvDictionary_IsContentObject(dictionary), "Expected a ContentObject"); + + CCNxContentObjectInterface *impl = (CCNxContentObjectInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary); + + if (impl == NULL) { + // If we're here, we need to update the implementation pointer. + // Figure out what the typeImplementation should be, based on the attributes we know. + int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); + + switch (schemaVersion) { + case CCNxTlvDictionary_SchemaVersion_V1: + impl = &CCNxContentObjectFacadeV1_Implementation; + break; + default: + trapUnexpectedState("Unknown SchemaVersion encountered in ccnxContentObjectInterface_GetInterface()"); + break; + } + + if (impl != NULL) { + // The cast to (CCNxTlvDictionary *) is to break the const. + ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl); + } + } + + return impl; +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h new file mode 100644 index 00000000..c2d67680 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +/** + * @brief A structure of functions representing a ContentObject implementation. + * + * The underlying implementation should support the CCNxContentObject API. + * + */ + +#ifndef CCNx_Common_ccnx_internal_ContentObjectInterface_h +#define CCNx_Common_ccnx_internal_ContentObjectInterface_h + +#include <parc/algol/parc_Buffer.h> + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> + +#include <ccnx/common/ccnx_Name.h> +#include <ccnx/common/ccnx_KeyLocator.h> +#include <ccnx/common/ccnx_PayloadType.h> + +typedef struct ccnx_contentobject_interface { + char *description; // A human-readable label for this implementation + + /** @see ccnxContentObject_CreateWithNameAndPayload */ + CCNxTlvDictionary *(*createWithNameAndPayload)(const CCNxName * contentName, + const CCNxPayloadType contentType, + const PARCBuffer * payload); + + /** @see ccnxContentObject_CreateWithPayload */ + CCNxTlvDictionary *(*createWithPayload)(const CCNxPayloadType contentType, + const PARCBuffer * payload); + + /** @see ccnxContentObject_GetName */ + CCNxName *(*getName)(const CCNxTlvDictionary * dict); + + /** @see ccnxContentObject_SetSignature */ + bool (*setSignature)(CCNxTlvDictionary *dict, + const PARCBuffer *keyId, + const PARCSignature *signature, + const CCNxKeyLocator *keyLocator); + + /** @see ccnxContentObject_GetKeyId */ + PARCBuffer *(*getKeyId)(const CCNxTlvDictionary * dict); + + /** @see ccnxContentObject_GetPayload */ + PARCBuffer *(*getPayload)(const CCNxTlvDictionary * dict); + + /** @see ccnxContentObject_GetPayloadType */ + CCNxPayloadType (*getPayloadType)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_SetPayload */ + bool (*setPayload)(CCNxTlvDictionary *dict, CCNxPayloadType payloadType, const PARCBuffer *payload); + + /** @see ccnxContentObject_SetFinalChunkNumber */ + bool (*setFinalChunkNumber)(CCNxTlvDictionary *dict, const uint64_t finalChunkNumber); + + /** @see ccnxContentObject_GetFinalChunkNumber */ + uint64_t (*getFinalChunkNumber)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_HasFinalChunkNumber */ + bool (*hasFinalChunkNumber)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_SetExpiryTime */ + bool (*setExpiryTime)(CCNxTlvDictionary *dict, const uint64_t expiryTime); + + /** @see ccnxContentObject_GetExpiryTime */ + uint64_t (*getExpiryTime)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_HasExpiryTime */ + bool (*hasExpiryTime)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_Equals */ + bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB); + + /** @see ccnxContentObject_AssertValid */ + void (*assertValid)(const CCNxTlvDictionary *dict); + + /** @see ccnxContentObject_ToString */ + char *(*toString)(const CCNxTlvDictionary * dict); + + /** @see ccnxContentObject_CreateWithPayload */ + void (*display)(const CCNxTlvDictionary *interestDictionary, size_t indentation); + + bool (*setPathLabel)(CCNxTlvDictionary *dict, const uint64_t pathLabel); + uint64_t (*getPathLabel)(const CCNxTlvDictionary *dict); + bool (*hasPathLabel)(const CCNxTlvDictionary *dict); +} CCNxContentObjectInterface; + +/** + * The SchemaV1 ContentObject implementaton + */ +extern CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation; + +/** + * Given a CCNxTlvDictionary representing a CCNxContentObject, return the address of the CCNxContentObjectInterface + * instance that should be used to access the ContentObject. This will also update the CCNxTlvDictionary's implementation + * pointer for future references. + * + * @param contentDictionary - a {@link CCNxTlvDictionary} representing a CCNxContentObject. + * @return the address of the `CCNxContentObjectInterface` instance that should be used to access the CCNxContentObject. + * + * Example: + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + * + * CCNxContentObject *contentObjectV0 = + * ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV0_Implementation, + * name, + * CCNxPayloadType_DATA, + * NULL); + * + * CCNxContentObject *contentObjectV1 = + * ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + * name, + * CCNxPayloadType_DATA, + * NULL); + * + * assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV0) == &CCNxContentObjectFacadeV0_Implementation, + * "Expected V0 Implementation"); + * + * assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation, + * "Expected V1 Implementation"); + * + * ccnxName_Release(&name); + * ccnxContentObject_Release(&contentObjectV0); + * ccnxContentObject_Release(&contentObjectV1); + * } + * @endcode + */ +CCNxContentObjectInterface *ccnxContentObjectInterface_GetInterface(const CCNxTlvDictionary *contentDictionary); +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c new file mode 100755 index 00000000..a0bb134a --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c @@ -0,0 +1,24 @@ +/* + * 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_InterestDefault.h" + +const uint32_t CCNxInterestDefault_LifetimeMilliseconds = -1; +const uint32_t CCNxInterestDefault_HopLimit = 255; +const CCNxInterestPayloadIdMethod CCNxInterestDefault_PayloadIdMethod = CCNxInterestPayloadIdMethod_App; + diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.h b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.h new file mode 100755 index 00000000..ebfc859a --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.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 ccnx_InterestDefault.h + * @brief Default values for various fields in an Interest + * + * Declares several constants that may be used when creating an Interest with default values. + * These may be used in a V0 or V1 Interest. + * + */ + +#ifndef __CCNx_Common__ccnx_InterestDefault__ +#define __CCNx_Common__ccnx_InterestDefault__ + +#include <inttypes.h> +#include <ccnx/common/internal/ccnx_InterestPayloadIdMethod.h> + +/** + * May be used in calls to create an Interest with the default lifetime. An Interest with + * the default lifetime does not encode the field in the wire format. + */ +extern const uint32_t CCNxInterestDefault_LifetimeMilliseconds; + +/** + * May be used in calls to create an Interest with the default hoplimit. + */ +extern const uint32_t CCNxInterestDefault_HopLimit; + +/** + * May be used in calls to create an Interest with the default payload id method. + * + * The PayloadIdMethod is a field inside the Interest that describes how the InterestPayloadId in the Name + * was calcuated. + */ +extern const CCNxInterestPayloadIdMethod CCNxInterestDefault_PayloadIdMethod; + +#endif /* defined(__CCNx_Common__ccnx_InterestDefault__) */ diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c new file mode 100644 index 00000000..5fca3cea --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c @@ -0,0 +1,295 @@ +/* + * 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 <ccnx/common/internal/ccnx_InterestFacadeV1.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> +#include <ccnx/common/internal/ccnx_InterestDefault.h> + + +// ===================== + +static void +_assertInvariants(const CCNxTlvDictionary *interestDictionary) +{ + assertNotNull(interestDictionary, "Dictionary is null"); + assertTrue((ccnxTlvDictionary_IsInterest(interestDictionary) || + ccnxTlvDictionary_IsInterestReturn(interestDictionary)), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(interestDictionary) == CCNxTlvDictionary_SchemaVersion_V1, + "Dictionary is wrong schema Interest, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(interestDictionary), CCNxTlvDictionary_SchemaVersion_V1); +} + +static uint32_t +_fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue) +{ + if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) { + return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key); + } + return defaultValue; +} + +static bool +_ccnxInterestFacadeV1_SetContentObjectHashRestriction(CCNxTlvDictionary *interestDictionary, const PARCBuffer *contentObjectHash) +{ + _assertInvariants(interestDictionary); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, contentObjectHash); + bool result = ccnxTlvDictionary_PutObject(interestDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION, + hash); + parcCryptoHash_Release(&hash); + return result; +} + +// forward declaration. Body below, in Getters. +static CCNxName * +_ccnxInterestFacadeV1_GetName(const CCNxTlvDictionary *interestDictionary); + +static bool +_ccnxInterestFacadeV1_SetPayloadWithId(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload, const CCNxInterestPayloadId *payloadId) +{ + bool result = false; + + if (payload) { + result = ccnxTlvDictionary_PutBuffer(interestDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + if (payloadId != NULL) { + CCNxName *name = _ccnxInterestFacadeV1_GetName(interestDictionary); + ccnxName_Append(name, ccnxInterestPayloadId_GetNameSegment(payloadId)); + } + } + return result; +} + +static bool +_ccnxInterestFacadeV1_SetPayloadAndId(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload) +{ + bool result = false; + + if (payload) { + CCNxInterestPayloadId *pid = ccnxInterestPayloadId_CreateAsSHA256Hash(payload); + _ccnxInterestFacadeV1_SetPayloadWithId(interestDictionary, payload, pid); + ccnxInterestPayloadId_Release(&pid); + } + return result; +} + +static bool +_ccnxInterestFacadeV1_SetPayload(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload) +{ + bool result = false; + + if (payload) { + _ccnxInterestFacadeV1_SetPayloadWithId(interestDictionary, payload, NULL); + } + return result; +} + +static bool +_ccnxInterestFacadeV1_SetLifetime(CCNxTlvDictionary *interestDictionary, uint32_t lifetimeInMillis) +{ + return ccnxTlvDictionary_PutInteger(interestDictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, lifetimeInMillis); +} + +static bool +_ccnxInterestFacadeV1_SetKeyIdRestriction(CCNxTlvDictionary *interestDictionary, const PARCBuffer *keyId) +{ + _assertInvariants(interestDictionary); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, keyId); + bool result = ccnxTlvDictionary_PutObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash); + parcCryptoHash_Release(&hash); + return result; +} + +static bool +_ccnxInterestFacadeV1_SetHopLimit(CCNxTlvDictionary *interestDictionary, uint32_t hopLimit) +{ + _assertInvariants(interestDictionary); + return ccnxTlvDictionary_PutInteger(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit); +} + +// ===================== +// Getters + +static CCNxName * +_ccnxInterestFacadeV1_GetName(const CCNxTlvDictionary *interestDictionary) +{ + int key = CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME; + _assertInvariants(interestDictionary); + if (ccnxTlvDictionary_IsValueName(interestDictionary, key)) { + return ccnxTlvDictionary_GetName(interestDictionary, key); + } + return NULL; +} + +static uint32_t +_ccnxInterestFacadeV1_GetLifetime(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + return _fetchUint32(interestDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, CCNxInterestDefault_LifetimeMilliseconds); +} + +static PARCBuffer * +_ccnxInterestFacadeV1_GetKeyIdRestriction(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION); + if (hash != NULL) { + return parcCryptoHash_GetDigest(hash); + } else { + return NULL; + } +} + +static PARCBuffer * +_ccnxInterestFacadeV1_GetContentObjectHashRestriction(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); + if (hash != NULL) { + return parcCryptoHash_GetDigest(hash); + } else { + return NULL; + } +} + +static PARCBuffer * +_ccnxInterestFacadeV1_GetPayload(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + return ccnxTlvDictionary_GetBuffer(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); +} + +static uint32_t +_ccnxInterestFacadeV1_GetHopLimit(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + return _fetchUint32(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, CCNxInterestDefault_HopLimit); +} + +// ===================== +// Miscellaneous + +static void +_ccnxInterestFacadeV1_AssertValid(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + assertTrue(ccnxTlvDictionary_IsValueName(interestDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME), "Name field is not a name"); +} + +static bool +_ccnxInterestFacadeV1_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b) +{ + return ccnxTlvDictionary_Equals(a, b); +} + +static void +_ccnxInterestFacadeV1_Display(const CCNxTlvDictionary *interestDictionary, size_t indentation) +{ + _assertInvariants(interestDictionary); + ccnxTlvDictionary_Display(interestDictionary, (unsigned) indentation); +} + + +// ===================== +// Creation + +static CCNxTlvDictionary * +_ccnxInterestFacadeV1_Create(const CCNxName *name, // required + const uint32_t lifetimeMilliseconds, // may use DefaultLimetimeMilliseconds + const PARCBuffer *keyId, // may be NULL + const PARCBuffer *contentObjectHash, // may be NULL + const uint32_t hopLimit) // may be DefaultHopLimit +{ + assertNotNull(name, "Parameter name must be non-null"); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + if (dictionary) { + ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + if (lifetimeMilliseconds != CCNxInterestDefault_LifetimeMilliseconds) { + _ccnxInterestFacadeV1_SetLifetime(dictionary, lifetimeMilliseconds); + } + + if (keyId) { + _ccnxInterestFacadeV1_SetKeyIdRestriction(dictionary, keyId); + } + + if (contentObjectHash) { + _ccnxInterestFacadeV1_SetContentObjectHashRestriction(dictionary, contentObjectHash); + } + + if (hopLimit != CCNxInterestDefault_HopLimit) { + _ccnxInterestFacadeV1_SetHopLimit(dictionary, hopLimit); + } + } else { + trapOutOfMemory("Could not allocate an Interest"); + } + + return dictionary; +} + +static CCNxTlvDictionary * +_ccnxInterestFacadeV1_CreateSimple(const CCNxName *name) +{ + return _ccnxInterestFacadeV1_Create(name, + CCNxInterestDefault_LifetimeMilliseconds, + NULL, // keyid + NULL, // content object hash + CCNxInterestDefault_HopLimit); +} + +CCNxInterestInterface CCNxInterestFacadeV1_Implementation = { + .description = "CCNxInterestFacadeV1_Implementation", + + .createSimple = &_ccnxInterestFacadeV1_CreateSimple, + .create = &_ccnxInterestFacadeV1_Create, + + .getName = &_ccnxInterestFacadeV1_GetName, + + .setContentObjectHashRestriction = &_ccnxInterestFacadeV1_SetContentObjectHashRestriction, + .getContentObjectHashRestriction = &_ccnxInterestFacadeV1_GetContentObjectHashRestriction, + + .setLifetime = &_ccnxInterestFacadeV1_SetLifetime, + .getLifetime = &_ccnxInterestFacadeV1_GetLifetime, + + .setKeyIdRestriction = &_ccnxInterestFacadeV1_SetKeyIdRestriction, + .getKeyIdRestriction = &_ccnxInterestFacadeV1_GetKeyIdRestriction, + + .getHopLimit = &_ccnxInterestFacadeV1_GetHopLimit, + .setHopLimit = &_ccnxInterestFacadeV1_SetHopLimit, + + .getPayload = &_ccnxInterestFacadeV1_GetPayload, + + .setPayload = &_ccnxInterestFacadeV1_SetPayload, + .setPayloadAndId = &_ccnxInterestFacadeV1_SetPayloadAndId, + .setPayloadWithId = &_ccnxInterestFacadeV1_SetPayloadWithId, + + .toString = NULL, + .equals = &_ccnxInterestFacadeV1_Equals, + .display = &_ccnxInterestFacadeV1_Display, + + .assertValid = &_ccnxInterestFacadeV1_AssertValid, +}; diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h new file mode 100755 index 00000000..29739f2c --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.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. + */ + +/** + * @file ccnx_InterestFacadeV1.h + * @ingroup Interest + * @brief A CCN Interest facade for an Interest over a CCNxTlvDictionary, using v1 schema. + * + */ +#ifndef libccnx_ccnx_InterestFacadeV1_h +#define libccnx_ccnx_InterestFacadeV1_h + +#include <ccnx/common/internal/ccnx_InterestInterface.h> + +extern CCNxInterestInterface CCNxInterestFacadeV1_Implementation; + +#endif // libccnx_ccnx_InterestFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c new file mode 100755 index 00000000..a507d69d --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c @@ -0,0 +1,53 @@ +/* + * 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 <LongBow/runtime.h> + +#include <ccnx/common/internal/ccnx_InterestInterface.h> + +CCNxInterestInterface * +ccnxInterestInterface_GetInterface(const CCNxTlvDictionary *dictionary) +{ + assertTrue((ccnxTlvDictionary_IsInterest(dictionary) || + ccnxTlvDictionary_IsInterestReturn(dictionary)), "Expected an Interest or InterestReturn"); + + CCNxInterestInterface *impl = (CCNxInterestInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary); + + if (impl == NULL) { + // If we're here, we need to update the interface pointer. + // Figure out what the typeInterface should be, based on the attributes we know. + int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); + + switch (schemaVersion) { + case CCNxTlvDictionary_SchemaVersion_V1: + impl = &CCNxInterestFacadeV1_Implementation; + break; + default: + trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestInterface_GetInterface()"); + break; + } + + if (impl == NULL) { + // The cast to (CCNxTlvDictionary *) is to break the const. + ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl); + } + } + return impl; +} + diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h new file mode 100644 index 00000000..bb78dfc3 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h @@ -0,0 +1,130 @@ +/* + * 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. + */ + +/** + * @brief A structure of functions representing an Interest implementation. + * + * The underlying implementation should support the CCNxInterest API. + * + */ + +#ifndef CCNx_Common_ccnx_internal_InterestInterface_h +#define CCNx_Common_ccnx_internal_InterestInterface_h + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> + +#include <ccnx/common/internal/ccnx_InterestPayloadIdMethod.h> +#include <ccnx/common/ccnx_InterestPayloadId.h> + +typedef struct ccnx_interest_interface { + /** A human-readable label for this implementation */ + char *description; + + /** @see ccnxInterest_Create */ + CCNxTlvDictionary *(*create)(const CCNxName * name, // required + const uint32_t lifetimeMilliseconds, // may use DefaultLimetimeMilliseconds + const PARCBuffer * keyId, // may be NULL + const PARCBuffer * contentObjectHash, // may be NULL + const uint32_t hopLimit); + + /** @see ccnxInterest_CreateSimple */ + CCNxTlvDictionary *(*createSimple)(const CCNxName * name); + + /** @see ccnxInterest_GetName */ + CCNxName *(*getName)(const CCNxTlvDictionary * dict); + + /** @see ccnxInterest_SetLifetime */ + bool (*setLifetime)(CCNxTlvDictionary *dict, uint32_t lifetime); + + /** @see ccnxInterest_GetLifetime */ + uint32_t (*getLifetime)(const CCNxTlvDictionary *dict); + + /** @see ccnxInterest_SetHopLimit */ + bool (*setHopLimit)(CCNxTlvDictionary *dict, uint32_t hopLimit); + + /** @see ccnxInterest_GetHopLimit */ + uint32_t (*getHopLimit)(const CCNxTlvDictionary *dict); + + /** @see ccnxInterest_SetKeyIdRestriction */ + bool (*setKeyIdRestriction)(CCNxTlvDictionary *dict, const PARCBuffer *keyId); + + /** @see ccnxInterest_GetKeyIdRestriction */ + PARCBuffer *(*getKeyIdRestriction)(const CCNxTlvDictionary * dict); + + /** @see ccnxInterest_SetPayload */ + bool (*setPayload)(CCNxTlvDictionary *dict, const PARCBuffer *payload); + + /** @see ccnxInterest_SetPayloadAndId */ + bool (*setPayloadAndId)(CCNxTlvDictionary *dict, const PARCBuffer *payload); + + /** @see ccnxInterest_SetPayloadWithId */ + bool (*setPayloadWithId)(CCNxTlvDictionary *dict, const PARCBuffer *payload, const CCNxInterestPayloadId *id); + + /** @see ccnxInterest_GetPayload */ + PARCBuffer *(*getPayload)(const CCNxTlvDictionary * dict); + + /** @see ccnxInterest_SetContentObjectHashRestriction */ + bool (*setContentObjectHashRestriction)(CCNxTlvDictionary *dict, const PARCBuffer *contentObjectHash); + + /** @see ccnxInterest_GetContentObjectHashRestriction */ + PARCBuffer *(*getContentObjectHashRestriction)(const CCNxTlvDictionary * dict); + + /** @see ccnxInterest_Equals */ + bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB); + /** @see ccnxInterest_AssertValid */ + void (*assertValid)(const CCNxTlvDictionary *dict); + + /** @see ccnxInterest_ToString */ + char *(*toString)(const CCNxTlvDictionary * dict); + /** @see ccnxInterest_Display */ + void (*display)(const CCNxTlvDictionary *interestDictionary, size_t indentation); +} CCNxInterestInterface; + + +/** + * The SchemaV1 Interest implementaton + */ +extern CCNxInterestInterface CCNxInterestFacadeV1_Implementation; + +/** + * Given a CCNxTlvDictionary representing a CCNxInterest, return the address of the CCNxInterestInterface + * instance that should be used to access the Interest. This will also update the CCNxTlvDictionary's interface + * pointer for future references. + * + * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterest. + * @return the address of the `CCNxContentObjectInterface` instance that should be used to access the CCNxInterest. + * + * Example: + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + * + * CCNxInterest *interestV1 = + * ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + * name, + * CCNxInterestDefault_LifetimeMilliseconds, + * NULL, + * NULL, + * CCNxInterestDefault_HopLimit); + * + * assertTrue(ccnxInterestInterface_GetInterface(interestV1) == &CCNxInterestFacadeV1_Implementation, + * "Expected V1 Implementation"); + * + * ccnxName_Release(&name); + * ccnxInterest_Release(&interestV1); + * } * @endcode + */ +CCNxInterestInterface *ccnxInterestInterface_GetInterface(const CCNxTlvDictionary *interestDictionary); +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h b/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h new file mode 100755 index 00000000..a29ddb9e --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h @@ -0,0 +1,28 @@ +/* + * 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 CCNx_Common_ccnx_InterestPayloadIdMethod_h +#define CCNx_Common_ccnx_InterestPayloadIdMethod_h + +typedef enum { + CCNxInterestPayloadIdMethod_App = 0, + CCNxInterestPayloadIdMethod_Nonce = 1, + CCNxInterestPayloadIdMethod_RFC6920 = 2 +} CCNxInterestPayloadIdMethod; + +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c new file mode 100755 index 00000000..80c1b718 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c @@ -0,0 +1,100 @@ +/* + * 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 <ccnx/common/internal/ccnx_InterestReturnFacadeV1.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +// ===================== + +static void +_assertInvariants(const CCNxTlvDictionary *interestDictionary) +{ + assertNotNull(interestDictionary, "Dictionary is null"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(interestDictionary), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(interestDictionary) == CCNxTlvDictionary_SchemaVersion_V1, + "Dictionary is wrong schema InterestReturn, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(interestDictionary), CCNxTlvDictionary_SchemaVersion_V1); +} + +static uint32_t +_fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue) +{ + if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) { + return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key); + } + return defaultValue; +} + +// ===================== +// Creation + +static CCNxTlvDictionary * +_ccnxInterestReturnFacadeV1_Create( + const CCNxInterest *interest, + CCNxInterestReturn_ReturnCode code) +{ + assertNotNull(interest, "Parameter name must be non-null"); + + assertTrue(ccnxInterestInterface_GetInterface(interest) == &CCNxInterestFacadeV1_Implementation, + "Non-V1 CCNxInterest passed to V1 ccnxInterestReturn_Create()"); + + CCNxInterestReturnFacadeV1_Implementation.interestImpl = CCNxInterestFacadeV1_Implementation; + + + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_ShallowCopy(interest); + + //Add InterestReturn specific stuff + ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, + CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_PutInteger(dictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode, + code); + + return dictionary; +} + +static void +_ccnxInterestReturnFacadeV1_AssertValid(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + assertTrue(ccnxTlvDictionary_IsValueName(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME), "Name field is not a name"); +} + +static CCNxInterestReturn_ReturnCode +_ccnxInterestReturnFacadeV1_GetReturnCode(const CCNxTlvDictionary *interestDictionary) +{ + _assertInvariants(interestDictionary); + CCNxInterestReturn_ReturnCode code = _fetchUint32(interestDictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode, + 0); + assertTrue(((code > 0) && (code < CCNxInterestReturn_ReturnCode_END)), "InterestReturn ReturnCode is out of ranage"); + + return code; +} + +CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation = { + .Create = &_ccnxInterestReturnFacadeV1_Create, + .AssertValid = &_ccnxInterestReturnFacadeV1_AssertValid, + .GetReturnCode = &_ccnxInterestReturnFacadeV1_GetReturnCode, +}; diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h new file mode 100755 index 00000000..e8aa0e37 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.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. + */ + +/** + * @file ccnx_InterestReturnFacadeV1.h + * @ingroup InterestReturn + * @brief A CCN InterestReturn facade over a CCNxTlvDictionary, using v1 schema. + * + */ +#ifndef libccnx_ccnx_InterestReturnFacadeV1_h +#define libccnx_ccnx_InterestReturnFacadeV1_h + +#include <ccnx/common/internal/ccnx_InterestReturnInterface.h> + +extern CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation; + +#endif // libccnx_ccnx_InterestReturnFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c new file mode 100755 index 00000000..2c9aa111 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c @@ -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. + */ + +/** + */ +#include <config.h> +#include <ccnx/common/internal/ccnx_InterestReturnInterface.h> + +#include <LongBow/runtime.h> + +CCNxInterestReturnInterface * +ccnxInterestReturnInterface_GetInterface(const CCNxTlvDictionary *dictionary) +{ + assertTrue(ccnxTlvDictionary_IsInterestReturn(dictionary), "Expected an InterestReturn"); + + CCNxInterestReturnInterface *impl = ccnxTlvDictionary_GetMessageInterface(dictionary); + + if (!impl) { + // If we're here, we need to update the interface pointer. Break the const. + // We're not changing data values, just initializing the Interface pointer. + + // Figure out what the typeInterface should be, based on the attributes we know. + int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); + + switch (schemaVersion) { + case CCNxTlvDictionary_SchemaVersion_V0: + trapUnexpectedState("ccnxInterestReturnInterface_GetInterface() not implemented for V0"); + case CCNxTlvDictionary_SchemaVersion_V1: + impl = &CCNxInterestReturnFacadeV1_Implementation; + break; + default: + trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestReturnInterface_GetInterface()"); + break; + } + + if (impl) { + ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, impl); // break the const. + } + } + + return impl; +} + diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h new file mode 100644 index 00000000..3f36fb90 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +/** + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ + +#ifndef CCNx_Common_ccnx_internal_InterestReturnInterface_h +#define CCNx_Common_ccnx_internal_InterestReturnInterface_h + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> +#include <ccnx/common/ccnx_InterestReturn.h> +#include <ccnx/common/ccnx_Interest.h> + + +typedef struct ccnx_interest_return_interface { + CCNxInterestInterface interestImpl; + + CCNxTlvDictionary *(*Create)(const CCNxInterest * interest, CCNxInterestReturn_ReturnCode code); + + bool (*Equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB); + void (*AssertValid)(const CCNxTlvDictionary *dict); + char *(*ToString)(const CCNxTlvDictionary * dict); + + uint32_t (*GetReturnCode)(const CCNxTlvDictionary *dict); +} CCNxInterestReturnInterface; + +extern CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation; + +/** + * Given a CCNxTlvDictionary representing a CCNxInterestReturn, return the address of the CCNxInterestReturnInterface + * instance that should be used to access the InterestReturn. + * + * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterestReturn. + * @return the address of the `CCNxInterestReturnInterface` instance that should be used to access the CCNxInterestReturn. + * + * Example: + * @code + * { + * + * CCNxInterest *interest = ...; + * CCNxInterestReturn *interestReturn = + * ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute); + * + * //V1 test + * if (ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation) { + * printf("Using a V1 CCNxInterestReturnInterface \n"); + * } + * + * ... + * + * ccnxInterestReturn_Release(&interestReturn); + * } * @endcode + */ +CCNxInterestReturnInterface *ccnxInterestReturnInterface_GetInterface(const CCNxTlvDictionary *interestDictionary); +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c new file mode 100644 index 00000000..e419d18e --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c @@ -0,0 +1,132 @@ +/* + * 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_JSON.h> + +#include <ccnx/common/ccnx_Manifest.h> +#include <ccnx/common/internal/ccnx_ManifestInterface.h> + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +static size_t _ccnxManifestFacadeV1_GetNumberOfHashGroups(const CCNxTlvDictionary *dict); + +static CCNxTlvDictionary * +_ccnxManifestFacadeV1_Create(const CCNxName *name) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + if (dictionary != NULL) { + if (name != NULL) { + ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + } + } else { + trapOutOfMemory("Could not allocate an Manifest"); + } + + return dictionary; +} + +static const CCNxName * +_ccnxManifestFacadeV1_GetName(const CCNxTlvDictionary *dict) +{ + return ccnxTlvDictionary_GetName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); +} + +static void +_ccnxManifestFacadeV1_AddHashGroup(CCNxTlvDictionary *dict, const CCNxManifestHashGroup *group) +{ + PARCJSON *json = ccnxManifestHashGroup_ToJson(group); + size_t numGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(dict); + + char *jsonString = parcJSON_ToString(json); + PARCBuffer *buffer = parcBuffer_AllocateCString(jsonString); + parcMemory_Deallocate(&jsonString); + parcJSON_Release(&json); + + ccnxTlvDictionary_PutListBuffer(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST, (uint32_t) numGroups, buffer); + parcBuffer_Release(&buffer); +} + +static CCNxManifestHashGroup * +_ccnxManifestFacadeV1_GetHashGroup(const CCNxTlvDictionary *dict, size_t index) +{ + PARCBuffer *buffer = NULL; + uint32_t key; + ccnxTlvDictionary_ListGetByPosition(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST, index, &buffer, &key); + + char *jsonString = parcBuffer_ToString(buffer); + PARCJSON *json = parcJSON_ParseString(jsonString); + parcMemory_Deallocate(&jsonString); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json); + parcJSON_Release(&json); + + return group; +} + +static size_t +_ccnxManifestFacadeV1_GetNumberOfHashGroups(const CCNxTlvDictionary *dict) +{ + size_t numHashGroups = ccnxTlvDictionary_ListSize(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST); + return numHashGroups; +} + +static bool +_ccnxManifestFacadeV1_Equals(const CCNxTlvDictionary *dictA, const CCNxTlvDictionary *dictB) +{ + if (dictA == dictB) { + return true; + } + if (dictA == NULL || dictB == NULL) { + return false; + } + + if (ccnxName_Equals(_ccnxManifestFacadeV1_GetName(dictA), _ccnxManifestFacadeV1_GetName(dictB))) { + if (_ccnxManifestFacadeV1_GetNumberOfHashGroups(dictA) == _ccnxManifestFacadeV1_GetNumberOfHashGroups(dictB)) { + for (size_t i = 0; i < _ccnxManifestFacadeV1_GetNumberOfHashGroups(dictA); i++) { + CCNxManifestHashGroup *groupA = _ccnxManifestFacadeV1_GetHashGroup(dictA, i); + CCNxManifestHashGroup *groupB = _ccnxManifestFacadeV1_GetHashGroup(dictB, i); + + if (!ccnxManifestHashGroup_Equals(groupA, groupB)) { + ccnxManifestHashGroup_Release(&groupA); + ccnxManifestHashGroup_Release(&groupB); + return false; + } + } + return true; + } + } + return false; +}; + +CCNxManifestInterface CCNxManifestFacadeV1_Interface = { + .description = "CCNxManifestFacadeV1_Implementation", + .create = &_ccnxManifestFacadeV1_Create, + .getName = &_ccnxManifestFacadeV1_GetName, + .addHashGroup = &_ccnxManifestFacadeV1_AddHashGroup, + .getHashGroup = &_ccnxManifestFacadeV1_GetHashGroup, + .getNumberOfHashGroups = &_ccnxManifestFacadeV1_GetNumberOfHashGroups, + .equals = &_ccnxManifestFacadeV1_Equals, +}; diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h new file mode 100755 index 00000000..0b5aab5a --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h @@ -0,0 +1,30 @@ +/* + * 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 ccnx_ManifestFacadeV1.h + * @ingroup Manifest + * @brief A CCN Manifest facade over a CCNxTlvDictionary, using V1 schema. + * + */ +#ifndef libccnx_ccnx_ManifestFacadeV1_h +#define libccnx_ccnx_ManifestFacadeV1_h + +#include <ccnx/common/internal/ccnx_ManifestInterface.h> + +extern CCNxManifestInterface CCNxManifestFacadeV1_Interface; + +#endif // libccnx_ccnx_ManifestFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c new file mode 100755 index 00000000..581eb93c --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c @@ -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. + */ + + +/** + */ +#include <config.h> + +#include <LongBow/runtime.h> + +#include <ccnx/common/ccnx_PayloadType.h> +#include <ccnx/common/internal/ccnx_ManifestInterface.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +CCNxManifestInterface * +ccnxManifestInterface_GetInterface(const CCNxTlvDictionary *dictionary) +{ + assertTrue(ccnxTlvDictionary_IsManifest(dictionary), "Expected a Manifest"); + + CCNxManifestInterface *impl = (CCNxManifestInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary); + + if (impl == NULL) { + // If we're here, we need to update the implementation pointer. + // Figure out what the typeImplementation should be, based on the attributes we know. + int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); + + switch (schemaVersion) { + case CCNxTlvDictionary_SchemaVersion_V1: + impl = &CCNxManifestFacadeV1_Interface; + break; + default: + trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestImplementation_GetImplementation()"); + break; + } + + if (impl == NULL) { + // The cast to (CCNxTlvDictionary *) is to break the const. + ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl); + } + } + + return impl; +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h new file mode 100644 index 00000000..75855b0c --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.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. + */ + + +/** + * @brief A structure of functions representing a Manifest implementation. + * + * The underlying implementation should support the CCNxManifest API. + * + */ + +#ifndef CCNx_Common_ccnx_internal_ManifestImpl_h +#define CCNx_Common_ccnx_internal_ManifestImpl_h + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> +#include <ccnx/common/ccnx_ManifestHashGroup.h> +#include <ccnx/common/ccnx_Name.h> +#include <ccnx/common/ccnx_KeyLocator.h> + +#include "ccnx_TlvDictionary.h" + +typedef struct ccnx_manifest_interface { + /** A human-readable label for this implementation */ + char *description; + + /** @see ccnxManifest_Create */ + CCNxTlvDictionary *(*create)(const CCNxName * name); + + /** @see ccnxManifest_AddHashGroup */ + void (*addHashGroup)(CCNxTlvDictionary *dict, const CCNxManifestHashGroup *group); + + /** @see ccnxManifest_GetHashGroup */ + CCNxManifestHashGroup *(*getHashGroup)(const CCNxTlvDictionary * dict, size_t index); + + /** @see ccnxManifest_GetNumberOfHashGroups */ + size_t (*getNumberOfHashGroups)(const CCNxTlvDictionary *dict); + + /** @see ccnxManifest_Equals */ + bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB); + + /** @see ccnxManifest_GetName */ + const CCNxName *(*getName)(const CCNxTlvDictionary * dict); +} CCNxManifestInterface; + +CCNxManifestInterface *ccnxManifestInterface_GetInterface(const CCNxTlvDictionary *dictionary); + +/** + * The SchemaV1 Manifest implementaton + */ +extern CCNxManifestInterface CCNxManifestFacadeV1_Interface; + +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h b/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h new file mode 100755 index 00000000..1f438348 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h @@ -0,0 +1,33 @@ +/* + * 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 CCNx_Common_ccnx_MessageInterface_h +#define CCNx_Common_ccnx_MessageInterface_h + +/** + * A type to represent the ContentObject/Interest/Control Interface pointer. The CCNxTlvDictionary + * maintains one that points to the appropriate interface implementation to reference the data + * contained in the CCNxTlvDictionary. For example, it might point to a CCNxContentObjectInterface, + * which would enable accessing the CCNxTlvDictionary as a ContentObject. + * + * + * @see CCNxContentObjectInterface + * @see CCNxInterestInterface + */ +typedef void CCNxMessageInterface; +#endif diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c new file mode 100755 index 00000000..3c768529 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c @@ -0,0 +1,1022 @@ +/* + * 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 <sys/time.h> +#include <inttypes.h> +#include <stdio.h> + +#include <ccnx/common/ccnx_Name.h> + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +#include <LongBow/runtime.h> + +#include <parc/algol/parc_DisplayIndented.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_JSON.h> + +#define DEBUG_ALLOCS 0 + +struct ccnx_tlv_dictionary_entry; +typedef struct ccnx_tlv_list_entry _CCNxTlvDictionaryListEntry; + +typedef enum { + CCNxTlvDictionaryType_Unknown, + CCNxTlvDictionaryType_Interest, + CCNxTlvDictionaryType_ContentObject, + CCNxTlvDictionaryType_Control, + CCNxTlvDictionaryType_InterestReturn, + CCNxTlvDictionaryType_Manifest +} _CCNxTlvDictionaryType; + +// These form a singly linked list +struct ccnx_tlv_list_entry { + _CCNxTlvDictionaryListEntry *next; + PARCBuffer *buffer; + uint16_t key; +}; + +#define ENTRY_UNSET ((int) 0) +#define ENTRY_BUFFER ((int) 1) +#define ENTRY_NAME ((int) 2) +#define ENTRY_INTEGER ((int) 3) +#define ENTRY_IOVEC ((int) 4) +#define ENTRY_JSON ((int) 5) +#define ENTRY_OBJECT ((int) 6) + +static struct dictionary_type_string { + _CCNxTlvDictionaryType type; + const char *string; +} ccnxTlvDictionaryTypeStrings [] = { + { .type = CCNxTlvDictionaryType_Unknown, .string = "Invalid" }, + { .type = CCNxTlvDictionaryType_Interest, .string = "Interest" }, + { .type = CCNxTlvDictionaryType_ContentObject, .string = "Content Object" }, + { .type = CCNxTlvDictionaryType_Control, .string = "Control" }, + { .type = CCNxTlvDictionaryType_InterestReturn, .string = "InterestReturn" }, + { .type = CCNxTlvDictionaryType_Manifest, .string = "Manifest" }, + { .type = UINT32_MAX, .string = NULL }, +}; + +static struct dictionary_entry_type_string { + int type; + const char *string; +} ccnxTlvDictionaryEntryTypeStrings [] = { + { .type = ENTRY_UNSET, .string = "Unset" }, + { .type = ENTRY_BUFFER, .string = "Buffer" }, + { .type = ENTRY_NAME, .string = "Name" }, + { .type = ENTRY_INTEGER, .string = "Integer" }, + { .type = ENTRY_IOVEC, .string = "IoVec" }, + { .type = ENTRY_JSON, .string = "JSON" }, + { .type = ENTRY_OBJECT, .string = "Object" }, + { .type = UINT32_MAX, .string = NULL }, +}; + +static const char *ccnxTlvDictionaryTypeUnknown = "Unknown"; + +static const char * +_ccnxTlvDictionaryEntryTypeToString(int entryType) +{ + for (int i = 0; ccnxTlvDictionaryEntryTypeStrings[i].string != NULL; i++) { + if (ccnxTlvDictionaryEntryTypeStrings[i].type == entryType) { + return ccnxTlvDictionaryEntryTypeStrings[i].string; + } + } + return ccnxTlvDictionaryTypeUnknown; +} + +static const char * +_ccnxTlvDictionaryTypeToString(_CCNxTlvDictionaryType dictionaryType) +{ + for (int i = 0; ccnxTlvDictionaryTypeStrings[i].string != NULL; i++) { + if (ccnxTlvDictionaryTypeStrings[i].type == dictionaryType) { + return ccnxTlvDictionaryTypeStrings[i].string; + } + } + return ccnxTlvDictionaryTypeUnknown; +} + + +typedef struct ccnx_tlv_dictionary_entry { + int entryType; + union u_entry { + PARCBuffer *buffer; + uint64_t integer; + CCNxName *name; + CCNxCodecNetworkBufferIoVec *vec; + PARCJSON *json; + PARCObject *object; + } _entry; +} _CCNxTlvDictionaryEntry; + +struct ccnx_tlv_dictionary { +#define FIXED_LIST_LENGTH 8 + // These are linked lists where we put unknown TLV types. This one static allocation should + // be enough for all the current packet formats. + _CCNxTlvDictionaryListEntry *fixedListHeads[FIXED_LIST_LENGTH]; + + // if we need to allocate beyond FIXED_LIST_LENGTH, put them here + _CCNxTlvDictionaryListEntry **extraListHeads; + + size_t fastArraySize; + size_t listSize; + + _CCNxTlvDictionaryType dictionaryType; + CCNxTlvDictionary_SchemaVersion schemaVersion; + + // Detects changes in the dictionary that were not caused by us + uint32_t generation; + + struct timeval creationTime; + + void (*infoFreeFunction)(void **infoPtr); + void *info; + + // A pointer to the implementation functions for the type contained by this dictionary. + // It's a runtime static, and is not encoded. Thus, when a dictionary is received over + // the wire, it will need to be initialized based on the dictionaryType and schemaVersion. + CCNxMessageInterface *messageInterface; + + // will be allocated as part of the ccnx_tlv_dictionary + _CCNxTlvDictionaryEntry directArray[CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END]; +}; + +static _CCNxTlvDictionaryListEntry * +_ccnxTlvDictionaryListEntry_Create(uint32_t key, const PARCBuffer *buffer) +{ + _CCNxTlvDictionaryListEntry *entry = parcMemory_AllocateAndClear(sizeof(_CCNxTlvDictionaryListEntry)); + assertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_CCNxTlvDictionaryListEntry)); + entry->key = key; + entry->buffer = parcBuffer_Acquire(buffer); + + return entry; +} + +static void +_ccnxTlvDictionaryListEntry_Release(_CCNxTlvDictionaryListEntry **entryPtr) +{ + _CCNxTlvDictionaryListEntry *entry = *entryPtr; + parcBuffer_Release(&entry->buffer); + parcMemory_Deallocate((void **) &entry); + *entryPtr = NULL; +} + +static void +_ccnxTlvDictionaryEntry_ListRelease(_CCNxTlvDictionaryListEntry **listHeadPtr) +{ + _CCNxTlvDictionaryListEntry *listHead = *listHeadPtr; + while (listHead) { + _CCNxTlvDictionaryListEntry *next = listHead->next; + _ccnxTlvDictionaryListEntry_Release(&listHead); + listHead = next; + } + *listHeadPtr = NULL; +} + +static void +_ccnxTlvDictionary_FinalRelease(CCNxTlvDictionary **dictionaryPtr) +{ + CCNxTlvDictionary *dictionary = *dictionaryPtr; + + // release any entries stored in the fast array + for (int i = 0; i < dictionary->fastArraySize; i++) { + switch (dictionary->directArray[i].entryType) { + case ENTRY_BUFFER: + parcBuffer_Release(&dictionary->directArray[i]._entry.buffer); + break; + case ENTRY_NAME: + ccnxName_Release(&dictionary->directArray[i]._entry.name); + break; + case ENTRY_IOVEC: + ccnxCodecNetworkBufferIoVec_Release(&dictionary->directArray[i]._entry.vec); + break; + case ENTRY_JSON: + parcJSON_Release(&dictionary->directArray[i]._entry.json); + break; + case ENTRY_OBJECT: + parcObject_Release(&dictionary->directArray[i]._entry.object); + break; + default: + // other types are direct storage + break; + } + } + + for (int i = 0; i < FIXED_LIST_LENGTH; i++) { + if (dictionary->fixedListHeads[i]) { + _ccnxTlvDictionaryEntry_ListRelease(&dictionary->fixedListHeads[i]); + } + } + + if (dictionary->extraListHeads) { + for (int i = FIXED_LIST_LENGTH; i < dictionary->listSize; i++) { + if (dictionary->extraListHeads[i - FIXED_LIST_LENGTH]) { + _ccnxTlvDictionaryEntry_ListRelease(&dictionary->extraListHeads[i - FIXED_LIST_LENGTH]); + } + } + parcMemory_Deallocate((void **) &(dictionary->extraListHeads)); + } + + if (dictionary->infoFreeFunction) { + dictionary->infoFreeFunction(&dictionary->info); + } + +#if DEBUG_ALLOCS + printf("finalize dictionary %p (final)\n", dictionary); +#endif +} + +parcObject_ExtendPARCObject(CCNxTlvDictionary, _ccnxTlvDictionary_FinalRelease, + NULL, NULL, ccnxTlvDictionary_Equals, NULL, NULL, NULL); + +parcObject_ImplementAcquire(ccnxTlvDictionary, CCNxTlvDictionary); + +parcObject_ImplementRelease(ccnxTlvDictionary, CCNxTlvDictionary); + +static void +_ccnxTlvDictionary_GetTimeOfDay(struct timeval *outputTime) +{ +#ifdef DEBUG + // if in debug mode, time messages + gettimeofday(outputTime, NULL); +#else + *outputTime = (struct timeval) { 0, 0 }; +#endif +} + + +CCNxTlvDictionary * +ccnxTlvDictionary_Create(size_t bufferCount, size_t listCount) +{ + CCNxTlvDictionary *dictionary = (CCNxTlvDictionary *) parcObject_CreateAndClearInstance(CCNxTlvDictionary); + + if (dictionary != NULL) { + _ccnxTlvDictionary_GetTimeOfDay(&dictionary->creationTime); + + dictionary->dictionaryType = CCNxTlvDictionaryType_Unknown; + dictionary->fastArraySize = bufferCount; + dictionary->listSize = listCount; + + dictionary->infoFreeFunction = NULL; + dictionary->info = NULL; + + dictionary->extraListHeads = NULL; + // dictionary->directArray is allocated as part of parcObject + } + +#if DEBUG_ALLOCS + printf("allocate dictionary %p\n", dictionary); +#endif + + return dictionary; +} + +CCNxTlvDictionary * +ccnxTlvDictionary_ShallowCopy(const CCNxTlvDictionary *source) +{ + size_t bufferCount = source->fastArraySize; + size_t listCount = source->listSize; + CCNxTlvDictionary *newDictionary = ccnxTlvDictionary_Create(bufferCount, listCount); + + if (newDictionary != NULL) { + newDictionary->dictionaryType = source->dictionaryType; + newDictionary->schemaVersion = source->schemaVersion; + newDictionary->generation = source->generation; + newDictionary->creationTime = source->creationTime; + newDictionary->messageInterface = source->messageInterface; + newDictionary->info = source->info; + newDictionary->infoFreeFunction = source->infoFreeFunction; + + // Update listHeads + for (uint32_t key = 0; key < source->listSize; ++key) { + size_t listSize = ccnxTlvDictionary_ListSize(source, key); + for (size_t i = 0; i < listSize; ++i) { + PARCBuffer *buffer; + uint32_t bKey; + ccnxTlvDictionary_ListGetByPosition(source, key, i, &buffer, &bKey); + parcBuffer_Acquire(buffer); + ccnxTlvDictionary_PutListBuffer(newDictionary, key, bKey, buffer); + parcBuffer_Release(&buffer); + } + } + + // Update directArray + for (uint32_t key = 0; key < source->fastArraySize; ++key) { + switch (source->directArray[key].entryType) { + case ENTRY_BUFFER: + ccnxTlvDictionary_PutBuffer(newDictionary, key, ccnxTlvDictionary_GetBuffer(source, key)); + break; + case ENTRY_NAME: + ccnxTlvDictionary_PutName(newDictionary, key, ccnxTlvDictionary_GetName(source, key)); + break; + case ENTRY_IOVEC: + ccnxTlvDictionary_PutIoVec(newDictionary, key, ccnxTlvDictionary_GetIoVec(source, key)); + break; + case ENTRY_JSON: + ccnxTlvDictionary_PutJson(newDictionary, key, ccnxTlvDictionary_GetJson(source, key)); + break; + case ENTRY_INTEGER: + ccnxTlvDictionary_PutInteger(newDictionary, key, ccnxTlvDictionary_GetInteger(source, key)); + break; + case ENTRY_OBJECT: + ccnxTlvDictionary_PutObject(newDictionary, key, ccnxTlvDictionary_GetObject(source, key)); + break; + default: + break; + } + } + } + + return newDictionary; +} + +bool +ccnxTlvDictionary_PutBuffer(CCNxTlvDictionary *dictionary, uint32_t key, const PARCBuffer *buffer) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(buffer, "Parameter buffer must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET) { + dictionary->directArray[key].entryType = ENTRY_BUFFER; + dictionary->directArray[key]._entry.buffer = parcBuffer_Acquire(buffer); + return true; + } + return false; +} + +bool +ccnxTlvDictionary_PutObject(CCNxTlvDictionary *dictionary, uint32_t key, const PARCObject *object) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(object, "Parameter object must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key %ud must be less than %zu", key, dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET) { + dictionary->directArray[key].entryType = ENTRY_OBJECT; + dictionary->directArray[key]._entry.object = parcObject_Acquire(object); + return true; + } + return false; +} + +bool +ccnxTlvDictionary_PutName(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxName *name) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(name, "Parameter buffer must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET) { + dictionary->directArray[key].entryType = ENTRY_NAME; + dictionary->directArray[key]._entry.name = ccnxName_Acquire(name); + return true; + } + return false; +} + +bool +ccnxTlvDictionary_PutInteger(CCNxTlvDictionary *dictionary, uint32_t key, const uint64_t value) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET || dictionary->directArray[key].entryType == ENTRY_INTEGER) { + dictionary->directArray[key].entryType = ENTRY_INTEGER; + dictionary->directArray[key]._entry.integer = value; + return true; + } + return false; +} + +bool +ccnxTlvDictionary_PutIoVec(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxCodecNetworkBufferIoVec *vec) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(vec, "Parameter buffer must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET) { + dictionary->directArray[key].entryType = ENTRY_IOVEC; + dictionary->directArray[key]._entry.vec = ccnxCodecNetworkBufferIoVec_Acquire((CCNxCodecNetworkBufferIoVec *) vec); + return true; + } + return false; +} + +bool +ccnxTlvDictionary_PutJson(CCNxTlvDictionary *dictionary, uint32_t key, const PARCJSON *json) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(json, "Parameter json must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_UNSET) { + dictionary->directArray[key].entryType = ENTRY_JSON; + dictionary->directArray[key]._entry.json = parcJSON_Acquire(json); + return true; + } + return false; +} + +CCNxCodecNetworkBufferIoVec * +ccnxTlvDictionary_GetIoVec(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_IOVEC) { + return dictionary->directArray[key]._entry.vec; + } + return NULL; +} + +// If you need to change the list head, use this +static _CCNxTlvDictionaryListEntry ** +_getListHeadReference(CCNxTlvDictionary *dictionary, uint32_t listKey) +{ + if (listKey < FIXED_LIST_LENGTH) { + return &dictionary->fixedListHeads[listKey]; + } else { + if (dictionary->extraListHeads == NULL) { + dictionary->extraListHeads = parcMemory_AllocateAndClear(sizeof(_CCNxTlvDictionaryListEntry *) * (dictionary->listSize - FIXED_LIST_LENGTH)); + } + + return &dictionary->extraListHeads[listKey - FIXED_LIST_LENGTH]; + } +} + +// If not going to modify the list, use this +static _CCNxTlvDictionaryListEntry * +_getListHead(const CCNxTlvDictionary *dictionary, uint32_t listKey) +{ + _CCNxTlvDictionaryListEntry **head = _getListHeadReference((CCNxTlvDictionary *) dictionary, listKey); + return *head; +} + +bool +ccnxTlvDictionary_PutListBuffer(CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t key, const PARCBuffer *buffer) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(buffer, "Parameter buffer must be non-null"); + assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize); + + _CCNxTlvDictionaryListEntry *entry = _ccnxTlvDictionaryListEntry_Create(key, buffer); + + _CCNxTlvDictionaryListEntry **head = _getListHeadReference(dictionary, listKey); + if (*head) { + // insert new value at list head + entry->next = *head; + *head = entry; + } else { + // new value is the list head + *head = entry; + } + return true; +} + +bool +ccnxTlvDictionary_IsValueBuffer(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_BUFFER); +} + +bool +ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_OBJECT); +} + +bool +ccnxTlvDictionary_IsValueInteger(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_INTEGER); +} + +bool +ccnxTlvDictionary_IsValueName(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_NAME); +} + +bool +ccnxTlvDictionary_IsValueIoVec(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_IOVEC); +} + +bool +ccnxTlvDictionary_IsValueJson(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + return (dictionary->directArray[key].entryType == ENTRY_JSON); +} + +PARCBuffer * +ccnxTlvDictionary_GetBuffer(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + // For now return NULL for backward compatability with prior code, case 1011 + if (dictionary->directArray[key].entryType == ENTRY_BUFFER) { + return dictionary->directArray[key]._entry.buffer; + } + return NULL; +} + +CCNxName * +ccnxTlvDictionary_GetName(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_NAME) { + return dictionary->directArray[key]._entry.name; + } + return NULL; +} + +uint64_t +ccnxTlvDictionary_GetInteger(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + trapIllegalValueIf(dictionary->directArray[key].entryType != ENTRY_INTEGER, + "Key %u is of type %d", + key, dictionary->directArray[key].entryType) + { + ccnxTlvDictionary_Display(dictionary, 3); + } + + return dictionary->directArray[key]._entry.integer; +} + + +PARCJSON * +ccnxTlvDictionary_GetJson(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_JSON) { + return dictionary->directArray[key]._entry.json; + } + return NULL; +} + +PARCObject * +ccnxTlvDictionary_GetObject(const CCNxTlvDictionary *dictionary, uint32_t key) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize); + + if (dictionary->directArray[key].entryType == ENTRY_OBJECT) { + return dictionary->directArray[key]._entry.object; + } + + return NULL; +} + +bool +ccnxTlvDictionary_ListGetByPosition(const CCNxTlvDictionary *dictionary, uint32_t listKey, size_t listPosition, PARCBuffer **bufferPtr, uint32_t *keyPtr) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertNotNull(bufferPtr, "Parameter bufferPtr must be non-null"); + assertNotNull(keyPtr, "Parameter keyPtr must be non-null"); + assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize); + + _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey); + while (entry) { + if (listPosition == 0) { + *bufferPtr = entry->buffer; + *keyPtr = entry->key; + return true; + } + entry = entry->next; + --listPosition; + } + + return false; +} + + +PARCBuffer * +ccnxTlvDictionary_ListGetByType(const CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t type) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize); + + PARCBuffer *buffer = NULL; + _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey); + while (entry) { + if (entry->key == type) { + buffer = entry->buffer; + break; + } + entry = entry->next; + } + + return buffer; +} + + +size_t +ccnxTlvDictionary_ListSize(const CCNxTlvDictionary *dictionary, uint32_t listKey) +{ + assertNotNull(dictionary, "Parameter dictionary must be non-null"); + assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize); + + size_t size = 0; + _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey); + while (entry) { + size++; + entry = entry->next; + } + + return size; +} + +void +ccnxTlvDictionary_SetMessageType_Interest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion) +{ + dictionary->dictionaryType = CCNxTlvDictionaryType_Interest; + dictionary->schemaVersion = schemaVersion; +} + +void +ccnxTlvDictionary_SetMessageType_ContentObject(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion) +{ + dictionary->dictionaryType = CCNxTlvDictionaryType_ContentObject; + dictionary->schemaVersion = schemaVersion; +} + +void +ccnxTlvDictionary_SetMessageType_Control(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion) +{ + dictionary->dictionaryType = CCNxTlvDictionaryType_Control; + dictionary->schemaVersion = schemaVersion; +} + +void +ccnxTlvDictionary_SetMessageType_InterestReturn(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion) +{ + dictionary->dictionaryType = CCNxTlvDictionaryType_InterestReturn; + dictionary->schemaVersion = schemaVersion; +} + +void +ccnxTlvDictionary_SetMessageType_Manifest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion) +{ + dictionary->dictionaryType = CCNxTlvDictionaryType_Manifest; + dictionary->schemaVersion = schemaVersion; +} + +bool +ccnxTlvDictionary_IsInterest(const CCNxTlvDictionary *dictionary) +{ + return (dictionary->dictionaryType == CCNxTlvDictionaryType_Interest); +} + +bool +ccnxTlvDictionary_IsInterestReturn(const CCNxTlvDictionary *dictionary) +{ + return (dictionary->dictionaryType == CCNxTlvDictionaryType_InterestReturn); +} + +bool +ccnxTlvDictionary_IsContentObject(const CCNxTlvDictionary *dictionary) +{ + return (dictionary->dictionaryType == CCNxTlvDictionaryType_ContentObject); +} + +bool +ccnxTlvDictionary_IsControl(const CCNxTlvDictionary *dictionary) +{ + return (dictionary->dictionaryType == CCNxTlvDictionaryType_Control); +} + +bool +ccnxTlvDictionary_IsManifest(const CCNxTlvDictionary *dictionary) +{ + return (dictionary->dictionaryType == CCNxTlvDictionaryType_Manifest); +} + +CCNxTlvDictionary_SchemaVersion +ccnxTlvDictionary_GetSchemaVersion(const CCNxTlvDictionary *dictionary) +{ + return dictionary->schemaVersion; +} + +void +ccnxTlvDictionary_SetMessageInterface(CCNxTlvDictionary *dictionary, const CCNxMessageInterface *implementation) +{ + dictionary->messageInterface = (CCNxMessageInterface *) implementation; +} + +CCNxMessageInterface * +ccnxTlvDictionary_GetMessageInterface(const CCNxTlvDictionary *dictionary) +{ + return dictionary->messageInterface; +} + +struct timeval +ccnxTlvDictionary_GetLifetime(const CCNxTlvDictionary *dictionary) +{ + struct timeval now; + _ccnxTlvDictionary_GetTimeOfDay(&now); + timersub(&now, &dictionary->creationTime, &now); + return now; +} + +static void +_ccnxTlvDictionary_DisplayBuffer(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.buffer); + parcBuffer_Display(entry->_entry.buffer, 6); +} + +static void +_ccnxTlvDictionary_DisplayInteger(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s value 0x%" PRIX64 " (%" PRIu64 ")\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), entry->_entry.integer, entry->_entry.integer); +} + +static void +_ccnxTlvDictionary_DisplayIoVec(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.vec); + ccnxCodecNetworkBufferIoVec_Display(entry->_entry.vec, 6); +} + +static void +_ccnxTlvDictionary_DisplayJson(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.json); + char *string = parcJSON_ToString(entry->_entry.json); + printf("%s\n", string); + parcMemory_Deallocate((void **) &string); +} + +static void +_ccnxTlvDictionary_DisplayName(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.name); + ccnxName_Display(entry->_entry.name, 6); +} + +static void +_ccnxTlvDictionary_DisplayUnknown(const _CCNxTlvDictionaryEntry *entry, int index) +{ + printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.buffer); +} + +static void +_ccnxTlvDictionary_DisplayListEntry(const _CCNxTlvDictionaryListEntry *entry, int listIndex, int position) +{ + printf(" List %3d Position %3d key 0x%04X pointer %p\n", listIndex, position, entry->key, (void *) entry->buffer); + parcBuffer_Display(entry->buffer, 6); +} + +void +ccnxTlvDictionary_Display(const CCNxTlvDictionary *dictionary, int indent) +{ + parcDisplayIndented_PrintLine(indent, "CCNxTlvDictionary@%p fastArraySize %zu listSize %zu dictionaryType %s schemaVersion %d refcount %" PRIu64 "\n", + (void *) dictionary, + dictionary->fastArraySize, + dictionary->listSize, + _ccnxTlvDictionaryTypeToString(dictionary->dictionaryType), + dictionary->schemaVersion, + parcObject_GetReferenceCount((PARCObject *) dictionary)); + + parcDisplayIndented_PrintLine(indent, " createTime %0.6f generation %u Info %p InfoFreeFunc %p\n", + (dictionary->creationTime.tv_sec + dictionary->creationTime.tv_usec * 1E-6), + dictionary->generation, + (void *) dictionary->info, + dictionary->infoFreeFunction); + + for (int i = 0; i < dictionary->fastArraySize; i++) { + if (dictionary->directArray[i].entryType != ENTRY_UNSET) { + switch (dictionary->directArray[i].entryType) { + case ENTRY_BUFFER: + _ccnxTlvDictionary_DisplayBuffer(&dictionary->directArray[i], i); + break; + + case ENTRY_INTEGER: + _ccnxTlvDictionary_DisplayInteger(&dictionary->directArray[i], i); + break; + + case ENTRY_IOVEC: + _ccnxTlvDictionary_DisplayIoVec(&dictionary->directArray[i], i); + break; + + case ENTRY_JSON: + _ccnxTlvDictionary_DisplayJson(&dictionary->directArray[i], i); + break; + + case ENTRY_NAME: + _ccnxTlvDictionary_DisplayName(&dictionary->directArray[i], i); + break; + + default: + _ccnxTlvDictionary_DisplayUnknown(&dictionary->directArray[i], i); + } + } + } + + for (int i = 0; i < dictionary->listSize; i++) { + _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, i); + if (entry) { + int position = 0; + printf(" Displaying custom entry list index %3d head %p\n", i, (void *) entry); + while (entry) { + _ccnxTlvDictionary_DisplayListEntry(entry, i, position); + entry = entry->next; + } + } + } +} + +static bool +_ccnxTlvDictionaryEntry_Equals(const _CCNxTlvDictionaryEntry *a, const _CCNxTlvDictionaryEntry *b) +{ + if (a == NULL && b == NULL) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + bool equals = false; + if (a->entryType == b->entryType) { + switch (a->entryType) { + case ENTRY_UNSET: + equals = true; + break; + + case ENTRY_BUFFER: + equals = parcBuffer_Equals(a->_entry.buffer, b->_entry.buffer); + break; + + case ENTRY_OBJECT: + equals = parcObject_Equals(a->_entry.object, b->_entry.object); + break; + + case ENTRY_INTEGER: + equals = (a->_entry.integer == b->_entry.integer); + break; + + case ENTRY_IOVEC: + equals = ccnxCodecNetworkBufferIoVec_Equals(a->_entry.vec, b->_entry.vec); + break; + + case ENTRY_JSON: + equals = parcJSON_Equals(a->_entry.json, b->_entry.json); + break; + + case ENTRY_NAME: + equals = ccnxName_Equals(a->_entry.name, b->_entry.name); + break; + + default: + trapIllegalValue(a->entryType, "Cannot compare due to unknown entry type: %d", a->entryType); + } + } + return equals; +} + +static bool +_ccnxTlvDictionaryListEntry_Equals(const _CCNxTlvDictionaryListEntry *a, const _CCNxTlvDictionaryListEntry *b) +{ + if (a == NULL && b == NULL) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + if (a->key == b->key) { + if (parcBuffer_Equals(a->buffer, b->buffer)) { + return true; + } + } + return false; +} + +static bool +_ccnxTlvDictionary_ListEquals(const _CCNxTlvDictionaryListEntry *listHeadA, const _CCNxTlvDictionaryListEntry *listHeadB) +{ + if (listHeadA == NULL && listHeadB == NULL) { + return true; + } + + if (listHeadA == NULL || listHeadB == NULL) { + return false; + } + + // walk both linked lists in parallel + while (listHeadA && listHeadB) { + if (!_ccnxTlvDictionaryListEntry_Equals(listHeadA, listHeadB)) { + return false; + } + + listHeadA = listHeadA->next; + listHeadB = listHeadB->next; + } + + // they must both be NULL otherwise the lists did not end at same place + if (listHeadA == NULL && listHeadB == NULL) { + return true; + } + return false; +} + +/* + * precondition: we know they are not null and they have the same fastarray size + */ +static bool +_ccnxTlvDictionary_FastArrayEquals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b) +{ + bool equals = true; + for (int i = 0; i < a->fastArraySize && equals; i++) { + equals = _ccnxTlvDictionaryEntry_Equals(&a->directArray[i], &b->directArray[i]); + } + return equals; +} + +/* + * preconditiona: we know they are not null and they have the same list size + */ +static bool +_ccnxTlvDictionary_ListsEquals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b) +{ + bool equals = true; + for (int i = 0; i < a->listSize && equals; i++) { + _CCNxTlvDictionaryListEntry *entry_a = _getListHead(a, i); + _CCNxTlvDictionaryListEntry *entry_b = _getListHead(b, i); + equals = _ccnxTlvDictionary_ListEquals(entry_a, entry_b); + } + return equals; +} + +bool +ccnxTlvDictionary_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b) +{ + if (a == NULL && b == NULL) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + // They are both non-null + bool equals = false; + if (a->fastArraySize == b->fastArraySize) { + if (a->listSize == b->listSize) { + if (a->dictionaryType == b->dictionaryType) { + if (a->schemaVersion == b->schemaVersion) { + if (_ccnxTlvDictionary_FastArrayEquals(a, b)) { + if (_ccnxTlvDictionary_ListsEquals(a, b)) { + equals = true; + } + } + } + } + } + } + return equals; +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h new file mode 100755 index 00000000..bae0ec8b --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h @@ -0,0 +1,1127 @@ +/* + * 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 ccnx_TlvDictionary.h + * @brief Stores pointers to PARCBuffers indexed by keys + * + * A message dictionary stores each field of a message in an array entry. The user of the dictionary needs to + * have a schema so it knows which array entry is which field. + * + * A message dictionary carries two distinguished fields that are not part of the array. The MessageType is + * Interest, ContentObject, or Control. The SchemaVersion is 0 or 1. These fields are independent of + * anything that is in the dictionary. + * + * The message dictionary creates two arrays. The first array is an array of PARCBuffer. The second array + * is a list of (type, PARCBuffer). This structure is designed such that well-known TLV keys + * are stored in the first array under well-known indicies. + * + * unknown TLV keys are stored in the second array, where each list corresponds to a TLV container. + * For example, an unknown TLV type found under the Content Object Metadata container would + * go in a list corresponding to the Metadata container and they be added to the list with the + * pair (type, PARCBuffer), where 'type' is the unknown TLV type. + * + */ + +#ifndef libccnx_ccnx_TlvDictionary_h +#define libccnx_ccnx_TlvDictionary_h + +#include <stdbool.h> +#include <sys/time.h> +#include <parc/algol/parc_Buffer.h> +#include <parc/algol/parc_JSON.h> + +#include <ccnx/common/internal/ccnx_MessageInterface.h> + +#include <ccnx/common/ccnx_Name.h> +#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h> + + +struct ccnx_tlv_dictionary; +typedef struct ccnx_tlv_dictionary CCNxTlvDictionary; + +typedef enum { + CCNxTlvDictionary_SchemaVersion_V0 = 0, + CCNxTlvDictionary_SchemaVersion_V1 = 1, +} CCNxTlvDictionary_SchemaVersion; + + +/** + * Creates a new TLV dictionary with the given size + * + * There will be 'bufferCount' array elements of type Buffer and + * 'listCount' elements of type List. Each array is indexed from 0. + * + * @param [in] bufferCount The number of Buffer elements to allocate within the dictionary. + * @param [in] listCount The number of List elements to allocate within the dictionary. + * + * @return NULL A new CCNxTlvDictionary object could not be allocated. + * @return CCNxTlvDictionary A new CCNxTlvDictionary instance with bufferCount Buffer and listCount List elements. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_PutBuffer(dict, 3, nameBuffer); + * rtatlvDictionary_PutListBuffer(dict, 2, unknownType, unknownBuffer); + * } + * @endcode + */ +CCNxTlvDictionary *ccnxTlvDictionary_Create(size_t bufferCount, size_t listCount); + +/** + * Acquire a handle to the CCNxTlvDictionary instance. + * + * Note that new instance is not created, + * only that the given instance's reference count is incremented. + * Discard the reference by invoking `ccnxTlvDictionary_Release()`. + * + * @param [in] dictionary A pointer to the original instance. + * @return The value of the input parameter @p instance. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Acquire(instance); + * + * ccnxTlvDictionary_Release(&dict); + * } + * @endcode + */ +CCNxTlvDictionary *ccnxTlvDictionary_Acquire(const CCNxTlvDictionary *dictionary); + +/** + * 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] dictionaryPtr A pointer to a pointer to the instance to release. + * + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Acquire(instance); + * + * ccnxTlvDictionary_Release(&dict); + * } + * @endcode + */ +void ccnxTlvDictionary_Release(CCNxTlvDictionary **dictionaryPtr); + +/** + * Adds a buffer to a dictionary entry + * + * Stores a reference count to the buffer + * + * @param [in] dictionary An CCNxTlvDictionary instance to which the Buffer entry will be added. + * @param [in] key The integer key that is to be associated with the new Buffer entry. + * @param [in] buffer The Buffer entry value to be inserted into the dictionary. + * + * @return true Key was not previously set + * @return false Key already has a buffer assigned to it + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutBuffer(dict, 1, buffer); + * // use the dictionary as needed + * } + * @endcode + */ +bool ccnxTlvDictionary_PutBuffer(CCNxTlvDictionary *dictionary, uint32_t key, const PARCBuffer *buffer); + +/** + * Determine if the value associated with the specified key is a Buffer. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * + * @param [in] dictionary The dictionary instance which will be examined. + * @param [in] key The key to use when indexing the dictionary. + * + * @return true The value associated with the key is of type Buffer. + * @return false The value associated with the key is -not- of type Buffer. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutBuffer(dict, 1, buffer); + * bool truthy = ccnxTlvDictionary_IsValueBuffer(dict, 1); + * // truthy will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueBuffer(const CCNxTlvDictionary *dictionary, uint32_t key); + +// caw TODO +bool ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Retrieves an entry from the dictionary from the specified key. + * + * @param [in] dictionary The dictionary instance which will be examined. + * @param [in] key The key to use when indexing the dictionary. + * + * @return NULL if key not found + * @return non-null The desired key + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutBuffer(dict, 1, buffer); + * PARCBuffer *copy = ccnxTlvDictionary_GetBuffer(dict, 1); + * // copy will be equal to the buffer instance + * } + * @endcode + */ +PARCBuffer *ccnxTlvDictionary_GetBuffer(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Put a new integer value in the dictionary, overwriting the old value if the key is + * already present. + * + * You can put an integer value many times, its OK to overwrite. + * They key must be UNSET or INTEGER, you cannot overwrite a different type + * The integer will be encoded as per the schema, it will not necessarily be an 8-byte field. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] key The key used when indexing the dictionary + * @param [in] value The new value to insert into the dictionary assoicated with the above key + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET/INTEGER type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * bool success = ccnxTlvDictionary_PutInteger(dict, 2, 1337); + * // success will be true since key 2 was UNSET + * } + * @endcode + */ +bool ccnxTlvDictionary_PutInteger(CCNxTlvDictionary *dictionary, uint32_t key, const uint64_t value); + +/** + * Determine if the value associated with the specified key is an Integer. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * + * @param [in] dictionary The dictionary instance which will be examined. + * @param [in] key The key to use when indexing the dictionary. + * + * @return true The value associated with the key is of type INTEGER. + * @return false The value associated with the key is -not- of type INTEGER. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_PutInteger(dict, 2, 1337); + * bool truthy = ccnxTlvDictionary_IsValueInteger(dict, 2); + * // truthy will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueInteger(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Returns an integer value stored in a key + * + * Will trapIllegalValue if the given key is not of type Integer. You should use + * ccnxTlvDictionary_IsValueInteger before calling. An unset key is not of type Integer. + * + * @param [in] dictionary The dictionary to check + * @param [in] key The key to retrieve + * + * @return number The value stored under the key + * + * Example: + * @code + * static uint32_t + * _fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue) + * { + * if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) { + * return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key); + * } + * return defaultValue; + * } + * @endcode + */ +uint64_t ccnxTlvDictionary_GetInteger(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Put a new CCNxName into the `CCNxTlvDictionary` instance. + * + * You can only set a Name field once. The key must be UNSET. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] key The key used when indexing the dictionary + * @param [in] name The new CCNxName value to insert into the dictionary assoicated with the above key + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar"); + * bool success = ccnxTlvDictionary_PutName(dict, 2, name); + * // success will be true since key 2 was UNSET + * } + * @endcode + */ +bool ccnxTlvDictionary_PutName(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxName *name); + +/** + * Determine if the value associated with the specified key is a CCNxName. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * + * @param [in] dictionary The dictionary instance which will be examined. + * @param [in] key The key to use when indexing the dictionary. + * + * @return true The value associated with the key is of type NAME. + * @return false The value associated with the key is -not- of type NAME. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar"); + * ccnxTlvDictionary_PutName(dict, 2, name); + * bool truthy = ccnxTlvDictionary_IsValueName(dict, 2); + * // truthy will be true since a name was inserted with key=2 + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueName(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Retrieve the CCNxName instance associated with the specified key. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * The entry is expected to be of type NAME, and will return NULL if not. + * + * @param [in] dictionary The dictionary instance which will be queried. + * @param [in] key The key to use when indexing the dictionary. + * + * @return NULL The entry associated with the key is not of type NAME. + * @return CCNxName A CCNxName instance associated with the specified key. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar"); + * ccnxTlvDictionary_PutName(dict, 2, name); + * CCNxName *copy = ccnxTlvDictionary_GetName(dict, 2); + * // do something with copy + * } + * @endcode + */ +CCNxName *ccnxTlvDictionary_GetName(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Insert a `CCNxCodecNetworkBufferIoVec` instance into the dictionary. + * + * Stores a scatter/gather network buffer. Could be either the wire format we recieve + * or the wire format we're about to send. The resulting entry type will be IOVEC. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] key The key used when indexing the dictionary + * @param [in] vec The new CCNxCodecNetworkBufferIoVec value to insert into the dictionary assoicated with the above key + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer); + * bool success = ccnxTlvDictionary_PutName(dict, 2, iovec); + * // success will be true since key 2 was UNSET + * } + * @endcode + */ +bool ccnxTlvDictionary_PutIoVec(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxCodecNetworkBufferIoVec *vec); + +/** + * Determine if the value associated with the specified key is a CCNxCodecNetworkBufferIoVec. + * + * @param [in] dictionary The dictionary instance to be examined + * @param [in] key The key used when indexing the dictionary + * + * @return true The TLV dictionary has the given key and it is of type IOVEC + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer); + * ccnxTlvDictionary_PutName(dict, 2, iovec); + * bool truthy = ccnxTlvDictionary_IsValueIoVec(dict, 2); + * // truthy will be true since key 2 was IOVEC and previously inserted + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueIoVec(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Retrieve the CCNxCodecNetworkBufferIoVec instance associated with the specified key. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * The entry is expected to be of type IOVEC, and will return NULL if not. + * + * @param [in] dictionary The dictionary instance which will be queried. + * @param [in] key The key to use when indexing the dictionary. + * + * @return NULL The entry associated with the key is not of type IOVEC. + * @return CCNxCodecNetworkBufferIoVec A CCNxCodecNetworkBufferIoVec instance associated with the specified key. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer); + * ccnxTlvDictionary_PutName(dict, 2, iovec); + * CCNxCodecNetworkBufferIoVec *copy = ccnxTlvDictionary_GetIoVec(dict, 2); + * // do something with copy + * } + * @endcode + */ +CCNxCodecNetworkBufferIoVec *ccnxTlvDictionary_GetIoVec(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Insert a new List item into the dictionary. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * You can only set a Buffer field once. The key must be UNSET. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] listKey The list key used when indexing the dictionary lists + * @param [in] key The key type of the element being inserted into the list + * @param [in] buffer The new PARCBuffer value to insert into the dictionary list indexed by the listKey + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * bool success = ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer); + * // success will be true since list key 1 was UNSET, and the new item will have key type 1 + * } + * @endcode + */ +bool ccnxTlvDictionary_PutListBuffer(CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t key, const PARCBuffer *buffer); + +/** + * Insert a new `PARCJSON` instance into the dictionary. + * + * The caller may destroy its reference to JSON since the type is deep-copied internally. + * The key must be within the dictionary, and the entry must be UNSET. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] key The key used when indexing the dictionary + * @param [in] json The new PARCJSON value to insert into the dictionary associated with the above key + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCJSON *json = ccnxJson_CreateNumber(1); + * bool success = ccnxTlvDictionary_PutJson(dict, 1, json); + * // success will be true since the key was UNSET + * } + * @endcode + */ +bool ccnxTlvDictionary_PutJson(CCNxTlvDictionary *dictionary, uint32_t key, const PARCJSON *json); + +/** + * Determine if the value associated with the specified key is a `PARCJSON` instance. + * + * @param [in] dictionary The dictionary instance to be examined + * @param [in] key The key used when indexing the dictionary + * + * @return true The TLV dictionary has the given key and it is of type JSON + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCJSON *json = ccnxJson_CreateNumber(1); + * ccnxTlvDictionary_PutJson(dict, 1, json); + * bool truthy = ccnxTlvDictionary_IsValueJson(dict, 1); + * // truthy will be true since the JSON object was previously inserted + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueJson(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Retrieve the `PARCJSON` instance associated with the specified key. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * The entry is expected to be of type JSON, and will return NULL if not. + * + * @param [in] dictionary The dictionary instance which will be queried. + * @param [in] key The key to use when indexing the dictionary. + * + * @return NULL The entry associated with the key is not of type JSON. + * @return PARCJSON A PARCJSON instance associated with the specified key. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCJSON *json = ccnxJson_CreateNumber(1); + * ccnxTlvDictionary_PutJson(dict, 1, json); + * PARCJSON *copy = ccnxTlvDictionary_GetJson(dict, 1); + * // do something with copy + * } + * @endcode + */ +PARCJSON *ccnxTlvDictionary_GetJson(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Insert a new `PARCJSON` instance into the dictionary. + * + * The caller may destroy its reference to PARCObject since the type is deep-copied internally. + * The key must be within the dictionary, and the entry must be UNSET. + * + * @param [in] dictionary The dictionary instance to be modified + * @param [in] key The key used when indexing the dictionary + * @param [in] json The new PARCObject value to insert into the dictionary associated with the above key + * + * @return true If the put/update was successful. + * @return false Otherwise (e.g., not UNSET type) + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCObject *object = ccnxName_CreateFromCString("ccnx/test"); + * bool success = ccnxTlvDictionary_PutObject(dict, 1, object); + * // success will be true since the key was UNSET + * } + * @endcode + */ +bool ccnxTlvDictionary_PutObject(CCNxTlvDictionary *dictionary, uint32_t key, const PARCObject *json); + +/** + * Determine if the value associated with the specified key is a `PARCObject` instance. + * + * @param [in] dictionary The dictionary instance to be examined + * @param [in] key The key used when indexing the dictionary + * + * @return true The TLV dictionary has the given key and it is of type PARCObject + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCObject *object = ccnxName_CreateFromCString("ccnx/test"); + * ccnxTlvDictionary_PutObject(dict, 1, object); + * bool truthy = ccnxTlvDictionary_IsValueObject(dict, 1); + * // truthy will be true since the PARCObject was previously inserted + * } + * @endcode + */ +bool ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Retrieve the `PARCObject` instance associated with the specified key. + * + * The key must be within the interval [0, bufferCount] for the dictionary. + * The entry is expected to be of type PARCObject, and will return NULL if not. + * + * @param [in] dictionary The dictionary instance which will be queried. + * @param [in] key The key to use when indexing the dictionary. + * + * @return NULL The entry associated with the key is not of type PARCObject. + * @return PARCObject A PARCObject instance associated with the specified key. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCObject *object = ccnxName_CreateFromCString("ccnx/test"); + * ccnxTlvDictionary_PutObject(dict, 1, object); + * PARCObject *copy = ccnxTlvDictionary_GetObject(dict, 1); + * // do something with copy + * } + * @endcode + */ +PARCObject *ccnxTlvDictionary_GetObject(const CCNxTlvDictionary *dictionary, uint32_t key); + +/** + * Fetches a buffer from the ordinal position 'listItem' from the list key 'key' + * + * The entry 'key' must be type list. + * + * @param [in] dictionary The dictionary instance being examined + * @param [in] listKey The key used to identify the list to be searched + * @param [in] listPosition The index within the target list of the dictionary + * @param [out] bufferPtr If position is found, the buffer at that position + * @param [out] keyPtr If position is found, the key of the buffer + * + * @return true position found + * @return false position not found + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer); + * PARCBuffer *copy = NULL; + * uint32_t key = 0; + * ccnxTlvDictionary_ListGetByPosition(dict, 1, 0, ©, &key); + * // use the copy and key as necessary + * } + * @endcode + */ +bool ccnxTlvDictionary_ListGetByPosition(const CCNxTlvDictionary *dictionary, uint32_t listKey, size_t listPosition, PARCBuffer **bufferPtr, uint32_t *keyPtr); + +/** + * Returns the first buffer in the list identified by 'listkey' with the buffer type 'type' + * + * @param [in] dictionary The dictionary instance being examined + * @param [in] listKey The key used to index into the dictionary lists + * @param [in] type The type of element used to search within the dictionary list + * + * @return PARCBuffer* Pointer to the first PARCBuffer instance whose type matches the type argument in the target list + * @return NULL If no element in the target list has the specified type. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer); + * PARCBuffer *copy = ccnxTlvDictionary_ListGetByType(dict, 1, 1); + * // copy and buffer will have equal PARCBuffer values + * } + * @endcode + */ +PARCBuffer *ccnxTlvDictionary_ListGetByType(const CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t type); + +/** + * Retrieve the number of elements in the list identified by 'key' + * + * The dictionary entry 'key' must be of type list. + * + * @param [in] dictionary The dictionary instance to be examined + * @param [in] listKey The key used to index into the list whose size will be checked + * + * @return The size of the list associated with the given list key + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer); + * size_t listSize = ccnxTlvDictionary_ListSize(dictionary, 1); + * // listSize will be 1 + * } + * @endcode + */ +size_t ccnxTlvDictionary_ListSize(const CCNxTlvDictionary *dictionary, uint32_t listKey); + +/** + * Set the type of message which this dictionary stores/represents to be an Interest. + * + * @param [in] dictionary The dictionary instance whose type is to be modified + * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0); + * // use the dictionary + * } + * @endcode + */ +void ccnxTlvDictionary_SetMessageType_Interest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion); + +/** + * Set the type of message which this dictionary stores/represents to be a ContentObject. + * + * @param [in] dictionary The dictionary instance whose type is to be modified + * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_ContentObject(dict, CCNxTlvDictionary_SchemaVersion_V1); + * // use the dictionary + * } + * @endcode + */ +void ccnxTlvDictionary_SetMessageType_ContentObject(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion); + +/** + * Set the type of message which this dictionary stores/represents to be a Control (message). + * + * @param [in] dictionary The dictionary instance whose type is to be modified + * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Control(dict, CCNxTlvDictionary_SchemaVersion_V1); + * // use the dictionary + * } + * @endcode + */ +void ccnxTlvDictionary_SetMessageType_Control(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion); + +/** + * Set the type of message which this dictionary stores/represents to be a Manifest (message). + * + * @param [in] dictionary The dictionary instance whose type is to be modified. + * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Manifest(dict, CCNxTlvDictionary_SchemaVersion_V1); + * // use the dictionary + * } + * @endcode + */ +void ccnxTlvDictionary_SetMessageType_Manifest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion); + +/** + * Set the type of message which this dictionary stores/represents to be an InterestReturn. + * + * @param [in] dictionary The dictionary instance whose type is to be modified + * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_InterestReturn(dict, CCNxTlvDictionary_SchemaVersion_V0); + * // use the dictionary + * } + * @endcode + */ +void ccnxTlvDictionary_SetMessageType_InterestReturn(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion); + + +/** + * Retrieve the schema version `CCNxTlvDictionary_SchemaVersion` used to encode the contents of the dictionary. + * + * Currently, only two schema versions are supported: CCNxTlvDictionary_SchemaVersion_V0 and CCNxTlvDictionary_SchemaVersion_V1 + * + * @param [in] dictionary The dictionary instance being examined + * + * @return The `CCNxTlvDictionary_SchemaVersion` version used for encoding. + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0); + * CCNxTlvDictionary_SchemaVersion ver = ccnxTlvDictionary_GetSchemaVersion(dict); + * // ver will be equal to CCNxTlvDictionary_SchemaVersion_V0 + * } + * @endcode + */ +CCNxTlvDictionary_SchemaVersion ccnxTlvDictionary_GetSchemaVersion(const CCNxTlvDictionary *dictionary); + +/** + * Determine if the specified dictionary represents an Interest message. + * + * @param [in] dictionary The dictionary instance being examined. + * + * @return true The dictionary represents an Interest message. + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0); + * bool isInterest = ccnxTlvDictionary_IsInterest(dict); + * // isInterest will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsInterest(const CCNxTlvDictionary *dictionary); + +/** + * Determine if the specified dictionary represents an InterestReturn message. + * + * @param [in] dictionary The dictionary instance being examined. + * + * @return true The dictionary represents an InterestReturn message. + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_InterestReturn(dict, CCNxTlvDictionary_SchemaVersion_V1); + * bool isInterestReturn = ccnxTlvDictionary_IsInterestReturn(dict); + * // isInterest will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsInterestReturn(const CCNxTlvDictionary *dictionary); + +/** + * Determine if the specified dictionary represents a ContentObject message. + * + * @param [in] dictionary The dictionary instance being examined. + * + * @return true The dictionary represents a ContentObject message. + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_ContentObject(dict, CCNxTlvDictionary_SchemaVersion_V0); + * bool isContentObject = ccnxTlvDictionary_IsContentObject(dict); + * // isContentObject will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsContentObject(const CCNxTlvDictionary *dictionary); + +/** + * Determine if the specified dictionary represents a Control message. + * + * @param [in] dictionary The dictionary instance being examined. + * + * @return true The dictionary represents a Control message. + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Control(dict, CCNxTlvDictionary_SchemaVersion_V0); + * bool isControl = ccnxTlvDictionary_IsControl(dict); + * // isControl will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsControl(const CCNxTlvDictionary *dictionary); + +/** + * Determine if the specified dictionary represents a Manifest message. + * + * @param [in] dictionary The dictionary instance being examined. + * + * @return true The dictionary represents a Manifest message. + * @return false Otherwise + * + * Example: + * @code + * { + * ... + * + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageType_Manifest(dict, CCNxTlvDictionary_SchemaVersion_V1); + * bool isManifest = ccnxTlvDictionary_IsManifest(dict); + * // isManifest will be true + * } + * @endcode + */ +bool ccnxTlvDictionary_IsManifest(const CCNxTlvDictionary *dictionary); + +/** + * If in DEBUG mode, returns how long the message has been in the system + * + * If not in DEBUG mode, will always be {.tv_sec = 0, .tv_usec = 0}. The time is based + * on gettimeofday(). + * + * Measured since the time when the dictionary was created + * + * @param [in] dictionary The dictionary instance whose lifetime is being queried + * + * @return struct timeval The lifetime of the dictionary message. + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * // do some things ... + * struct timeval = ccnxTlvDictionary_GetLifetime(dict); + * // use the time as needed + * } + * @endcode + */ +struct timeval ccnxTlvDictionary_GetLifetime(const CCNxTlvDictionary *dictionary); + +/** + * Display the dictionary and its contents + * + * The contents of the dictionary are printed to stdout. This is often useful + * for verbose debugging purposes. + * + * @param [in] indent The number of tabs to indent all lines printed on stdout + * @param [in] dictionary The dictionary instance whose contents will be printed to stdout + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_Display(dict, 0); + * } + * @endcode + */ +void ccnxTlvDictionary_Display(const CCNxTlvDictionary *dictionary, int indent); + +/** + * Determine if two CCNxTlvDictionary instances are equal. + * + * Two CCNxTlvDictionary instances are equal if, and only if, they contain the same number + * of keys, the keys are equal, and each key points to the same value. + * + * The following equivalence relations on non-null `CCNxTlvDictionary` instances are maintained: + * + * * It is reflexive: for any non-null reference value x, `ccnxTlvDictionary_Equals(x, x)` + * must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `ccnxTlvDictionary_Equals(x, y)` must return true if and only if + * `ccnxTlvDictionary_Equals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `ccnxTlvDictionary_Equals(x, y)` returns true and + * `ccnxTlvDictionary_Equals(y, z)` returns true, + * then `ccnxTlvDictionary_Equals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `ccnxTlvDictionary_Equals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `ccnxTlvDictionary_Equals(x, NULL)` must + * return false. + * + * @param a A pointer to a `CCNxTlvDictionary` instance. + * @param b A pointer to a `CCNxTlvDictionary` instance. + * + * NULL == NULL, non-NULL != NULL, otherwise the dictionaries need to be the same + * type, schema, and all fields must compare for equality. + * + * Equals does not include the CreationTime (lifetime) or the SetInfo() value. + * + * @return true Dictionaries are equal + * @return false Dictionaries differ in some way + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *dict1 = ccnxTlvDictionary_Create(5, 3); + * CCNxTlvDictionary *dict2 = ccnxTlvDictionary_Create(5, 3); + * if (ccnxTlvDictionary_Equals(dict1, dict2)) { + * // true + * } else { + * // false + * } + * } + * @endcode + */ +bool ccnxTlvDictionary_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b); + +/** + * Allocates a new instance of the specified CCNxTlvDictionary that is + * a "Shallow" copy of the original. The new instance contains the + * same contents as the original CCNxTlvDictionary but an Acquire() + * operation is used where possible to form a new link to the original + * contained content (a Copy() operation is used otherwise). Note that + * this means that modifying the content of the copy will, in most + * cases, modify the content of the original. In any case, the + * contents are protected from premature deallocation. + * + * @param [in] source The dictionary to copy + * + * @return CCNxTlvDictionary A pointer to a copy of the source dictionary + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *source = ccnxTlvDictionary_Create(5, 3); + * PARCBuffer *buffer = parcBuffer_Allocate(1); + * ccnxTlvDictionary_PutListBuffer(source, 1, 1, buffer); + * ... + * CCNxTlvDictionary *copy = ccnxTlvDictionary_ShallowCopy(source); + * PARCBuffer *buffcopy; + * uint32_t key = 0; + * ccnxTlvDictionary_ListGetByPosition(copy, 1, 0, &buffcopy, &key); + * ... + * assertTrue(ccnxTlvDictionary_Equals(source, copy), "Error: not a copy"); + * assertTrue(buffcopy == buffer, "Error: not a shallow copy"); + * } + * @endcode + */ +CCNxTlvDictionary *ccnxTlvDictionary_ShallowCopy(const CCNxTlvDictionary *source); + +/** + * Set the pointer to the implementation used to create the message type represented by this + * CCNxTlvDictionary. For example, if the CCNxTlvDictionary represents a V1 ContentObject, + * the implementation pointer should be set to &CCNxContentObjectFacadeV1_Implementation. + * The type can be inferred from the dictionary's schemaVersion and messageType. + * + * Consumers of this CCNxTlvDictionary should use the implementation pointer to access + * fields in the dictionary. Examples of implementations would be those that define + * {@link CCNxContentObjectInterface} or {@link CCNxInterestInterface}, such as + * {@link CCNxContentObjectFacadeV1_Implementation} or {CCNxInterestFacadeV1_Implementation}. + * + * @param [in] dictionary The dictionary instance on which to set the implementation pointer. + * @param [in] implementation The address of the implementation to be used to access this dictionary. + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageInterface(&CCNxContentObjectFacadeV1_Implementation); + * } + * @endcode + * @see `ccnxTlvDictionary_GetMessageTypeInterface` + */ +void ccnxTlvDictionary_SetMessageInterface(CCNxTlvDictionary *dictionary, const CCNxMessageInterface *implementation); + +/** + * Return the address of the implementation used to access fields in the the message represented by this + * CCNxTlvDictionary instance. The implementation pointer would typically be + * {@link CCNxContentObjectFacadeV1_Implementation} or {@link CCNxContentObjectFacadeV1_Implementation}. + * If it is not set, it can be inferred from the messageType and the schemaVersion. + * + * @param [in] dictionary The dictionary instance from which to retrieve the implementation pointer. + * + * Example: + * @code + * { + * ... + * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3); + * ccnxTlvDictionary_SetMessageTypeInterface(&CCNxContentObjectFacadeV1_Implementation); + * CCNxContentObjectInterface *impl = ccnxTlvDictionary_GetMessageTypeInterface(dict); + * } + * @endcode + * @see `ccnxTlvDictionary_SetMessageTypeInterface` + * @see `ccnxContentObjectInterface_GetInterface` + * @see `ccnxInterestInterface_GetInterface` + */ +CCNxMessageInterface *ccnxTlvDictionary_GetMessageInterface(const CCNxTlvDictionary *dictionary); +#endif // libccnx_ccnx_TlvDictionary_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvError.c b/libccnx-common/ccnx/common/internal/ccnx_TlvError.c new file mode 100755 index 00000000..0f07ab9e --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_TlvError.c @@ -0,0 +1,167 @@ +/* + * 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/internal/ccnx_TlvError.h> + +struct error_messages { + CCNxTlvErrorCodes 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" }, + + // end of list sentinel, the NULL determines the end of list + { .code = UINT16_MAX, .message = NULL } +}; + + +const char * +ccnxTlvErrors_ErrorMessage(CCNxTlvErrorCodes 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_tlv_error { + CCNxTlvErrorCodes code; + const char *functionName; + int line; + size_t byteOffset; + unsigned refcount; + char *toString; +}; + +CCNxTlvError * +ccnxTlvError_Create(CCNxTlvErrorCodes code, const char *func, int line, size_t byteOffset) +{ + CCNxTlvError *error = parcMemory_AllocateAndClear(sizeof(CCNxTlvError)); + assertNotNull(error, "parcMemory_AllocateAndClear(%u) returned NULL", sizeof(CCNxTlvError)); + error->code = code; + error->functionName = func; + error->line = line; + error->byteOffset = byteOffset; + error->toString = NULL; // computed on the fly + error->refcount = 1; + return error; +} + +CCNxTlvError * +ccnxTlvError_Acquire(CCNxTlvError *error) +{ + assertNotNull(error, "Parameter error must be non-null"); + assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid"); + + error->refcount++; + return error; +} + +void +ccnxTlvError_Release(CCNxTlvError **errorPtr) +{ + assertNotNull(errorPtr, "Parameter must be non-null double pointer"); + assertNotNull(*errorPtr, "Parameter must derefernece to non-null pointer"); + CCNxTlvError *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 +ccnxTlvError_GetByteOffset(const CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + return error->byteOffset; +} + + +CCNxTlvErrorCodes +ccnxTlvError_GetErrorCode(const CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + return error->code; +} + +const char * +ccnxTlvError_GetFunction(const CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + return error->functionName; +} + +int +ccnxTlvError_GetLine(const CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + return error->line; +} + +const char * +ccnxTlvError_GetErrorMessage(const CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + return ccnxTlvErrors_ErrorMessage(error->code); +} + +const char * +ccnxTlvError_ToString(CCNxTlvError *error) +{ + assertNotNull(error, "Parameter must be non-null"); + if (error->toString) { + return error->toString; + } + + asprintf(&error->toString, "TLV error: %s:%d offset %zu: %s", + error->functionName, + error->line, + error->byteOffset, + ccnxTlvError_GetErrorMessage(error)); + + return error->toString; +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c new file mode 100755 index 00000000..d9f86895 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c @@ -0,0 +1,203 @@ +/* + * 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 <ccnx/common/internal/ccnx_ValidationFacadeV1.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +static void +_assertInvariants(const CCNxTlvDictionary *message) +{ + assertNotNull(message, "Parameter message must be non-null"); +} + +PARCBuffer * +ccnxValidationFacadeV1_GetKeyId(const CCNxTlvDictionary *message) +{ + _assertInvariants(message); + return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); +} + +CCNxLink * +ccnxValidationFacadeV1_GetKeyName(const CCNxTlvDictionary *message) +{ + _assertInvariants(message); + CCNxLink *link = NULL; + CCNxName *name = ccnxTlvDictionary_GetName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME); + if (name) { + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID); + PARCBuffer *hash = ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH); + + link = ccnxLink_Create(name, keyid, hash); + } + return link; +} + +PARCBuffer * +ccnxValidationFacadeV1_GetPublicKey(const CCNxTlvDictionary *message) +{ + _assertInvariants(message); + return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); +} + +PARCBuffer * +ccnxValidationFacadeV1_GetCertificate(const CCNxTlvDictionary *message) +{ + _assertInvariants(message); + return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); +} + +PARCBuffer * +ccnxValidationFacadeV1_GetPayload(const CCNxTlvDictionary *message) +{ + _assertInvariants(message); + return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); +} + +bool +ccnxValidationFacadeV1_HasCryptoSuite(const CCNxTlvDictionary *message) +{ + bool hasCryptoSuite = false; + _assertInvariants(message); + if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) { + hasCryptoSuite = true; + } + return hasCryptoSuite; +} + +PARCCryptoSuite +ccnxValidationFacadeV1_GetCryptoSuite(const CCNxTlvDictionary *message) +{ + if (ccnxValidationFacadeV1_HasCryptoSuite(message)) { + return (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + } + + trapUnexpectedState("Dictionary does not have a CryptoSuite set"); +} + +bool +ccnxValidationFacadeV1_HasSigningTime(const CCNxTlvDictionary *message) +{ + bool hasSigningTime = false; + _assertInvariants(message); + if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME)) { + hasSigningTime = true; + } + return hasSigningTime; +} + +uint64_t +ccnxValidationFacadeV1_GetSigningTime(const CCNxTlvDictionary *message) +{ + if (ccnxValidationFacadeV1_HasSigningTime(message)) { + return ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + } + + trapUnexpectedState("Dictionary does not have a CryptoSuite set"); +} + +// =========================================================== +// Setters + +bool +ccnxValidationFacadeV1_SetKeyId(CCNxTlvDictionary *message, const PARCBuffer *keyid) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid); +} + +bool +ccnxValidationFacadeV1_SetKeyName(CCNxTlvDictionary *message, const CCNxLink *keyNameLink) +{ + _assertInvariants(message); + const CCNxName *name = ccnxLink_GetName(keyNameLink); + bool success = ccnxTlvDictionary_PutName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name); + if (success) { + PARCBuffer *keyid = ccnxLink_GetKeyID(keyNameLink); + if (keyid) { + success = ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID, keyid); + } + + if (success) { + PARCBuffer *hash = ccnxLink_GetContentObjectHash(keyNameLink); + success = ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH, hash); + } + } + return success; +} + +bool +ccnxValidationFacadeV1_SetKeyLocator(CCNxTlvDictionary *message, CCNxKeyLocator *keyLocator) +{ + bool success = true; + if (keyLocator) { + if (ccnxKeyLocator_IsKey(keyLocator)) { + PARCKey *key = ccnxKeyLocator_GetKey(keyLocator); + PARCBuffer *keybuffer = parcKey_GetKey(key); + success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY, keybuffer); + } else if (ccnxKeyLocator_IsKeyLink(keyLocator)) { + CCNxLink *link = ccnxKeyLocator_GetKeyLink(keyLocator); + const CCNxName *name = ccnxLink_GetName(link); + + // Support KeyId and COH as part of the keyname, case 1012 + success &= ccnxTlvDictionary_PutName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name); + } else { + trapUnrecoverableState("KeyLocator is not a known type"); + } + } + return success; +} + +bool +ccnxValidationFacadeV1_SetPublicKey(CCNxTlvDictionary *message, const PARCBuffer *derEncodedKey) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY, derEncodedKey); +} + +bool +ccnxValidationFacadeV1_SetCertificate(CCNxTlvDictionary *message, const PARCBuffer *derEncodedCertificate) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT, derEncodedCertificate); +} + +bool +ccnxValidationFacadeV1_SetCryptoSuite(CCNxTlvDictionary *message, PARCCryptoSuite suite) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); +} + +bool +ccnxValidationFacadeV1_SetSigningTime(CCNxTlvDictionary *message, uint64_t signingTime) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME, signingTime); +} + +bool +ccnxValidationFacadeV1_SetPayload(CCNxTlvDictionary *message, const PARCBuffer *validationPayload) +{ + _assertInvariants(message); + return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, validationPayload); +} + diff --git a/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h new file mode 100644 index 00000000..524efe7e --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h @@ -0,0 +1,474 @@ +/* + * 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 ccnx_ValidationFacadeV1.h + * @brief Generic functions to fetch/set the KeyId, PublicKey, Certificate, or validation payload + * + * The Validation Facade may be used directly on CCNxInterest or CCNxContentObject structures, for example: + * + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL); + * ccnxName_Release(&name); + * // generate the KeyId + * ccnxValidationFacadeV1_SetKeyId(object, keyId); + * } + * @endcode + * + */ + +#ifndef libccnx_ccnx_ValidationFacadeV1_h +#define libccnx_ccnx_ValidationFacadeV1_h + +#include <parc/algol/parc_Buffer.h> + +#include <ccnx/common/ccnx_KeyLocator.h> + +#include <ccnx/common/ccnx_Link.h> +#include <ccnx/common/internal/ccnx_TlvDictionary.h> +#include <parc/security/parc_CryptoSuite.h> + + +// =========================================================== +// Validation Algorithm + +#include <ccnx/common/validation/ccnxValidation_CRC32C.h> +#include <ccnx/common/validation/ccnxValidation_EcSecp256K1.h> +#include <ccnx/common/validation/ccnxValidation_HmacSha256.h> +#include <ccnx/common/validation/ccnxValidation_RsaSha256.h> + +// =========================================================== +// Getters + +/** + * If the Validation Algorithm has a KeyId field, return it if it exists + * + * Not all validation algorithms have a KeyId field. Only true signature algoritms, such as + * RSA or ECC should always have one. HMAC or other MACs often use the KeyId to identify a + * key agreed to via a key exchange protocol, so the meaning is only applicable to those parties. + * Integrity checks, such as CRC-32C, do not have a KeyId. + * + * @param [in] message An allocated dictionary + * + * @retval non-null The KeyId field of the Validation Algorithm + * @retval null KeyId is missing + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * PARCBuffer *keyid = ccnxValidationFacadeV1_GetKeyId(dictionary); + * } + * @endcode + */ +PARCBuffer *ccnxValidationFacadeV1_GetKeyId(const CCNxTlvDictionary *message); + +/** + * If the Validation Algorithm has a KeyName, return the embedded Link + * + * The returned CCNxLink is allocated on function call, so caller must + * release it when done. + * + * @param [in] message An allocated dictionary + * + * @retval non-null The KeyName link of the Validation Algorithm (must be released) + * @retval null KeyName is missing + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * CCNxLink *link = ccnxValidationFacadeV1_GetKeyName(dictionary); + * } + * @endcode + */ +CCNxLink *ccnxValidationFacadeV1_GetKeyName(const CCNxTlvDictionary *mesage); + +/** + * If the Validation Algorithm has a Public Key embedded, return it + * + * @param [in] message An allocated dictionary + * + * @retval non-null The KeyId field of the Validation Algorithm + * @retval null KeyId is missing + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * PARCBuffer *publicKeyDEREncoding = ccnxValidationFacadeV1_GetPublicKey(dictionary); + * } + * @endcode + */ +PARCBuffer *ccnxValidationFacadeV1_GetPublicKey(const CCNxTlvDictionary *message); + +/** + * If the Validation Algorithm has a Certificate embedded, return it + * + * @param [in] message An allocated dictionary + * + * @retval non-null The Certificate field of the Validation Algorithm + * @retval null KeyId is missing + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * PARCBuffer *x509certDEREncoding = ccnxValidationFacadeV1_GetCertificate(dictionary); + * } + * @endcode + */ +PARCBuffer *ccnxValidationFacadeV1_GetCertificate(const CCNxTlvDictionary *message); + +/** + * Returns the Validation Payload, if present. + * + * The validation payload is the actual bytes of the signature or authentication code or + * integrity check. it's format will be specific to the ValidationAlgorithm. + * + * @param [in] message An allocated dictionary + * + * @retval non-null The validation payload + * @retval null Validation payload does not exist + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * PARCBuffer *validationPayload = ccnxValidationFacadeV1_GetPayload(dictionary); + * } + * @endcode + */ +PARCBuffer *ccnxValidationFacadeV1_GetPayload(const CCNxTlvDictionary *message); + +/** + * Determines if the packet specified a supported crypto suite + * + * @param [in] message An allocated dictionary + * + * @retval true There is a valid crypto suite specified + * @retval false There is not a valid crypto suite specified + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * if (ccnxValidationFacadeV1_HasCryptoSuite(dictionary)) { + * PARCCryptoSuite suite = ccnxValidationFacadeV1_GetCryptoSuite(dictionary); + * // process the validation alg + * } + * } + * @endcode + */ +bool ccnxValidationFacadeV1_HasCryptoSuite(const CCNxTlvDictionary *message); + +/** + * Returns the Validation Algorithm specified in the packet + * + * If the packet specified a supported crypto suite, return the suite. If + * it is not a supported algorithm, function all assert an error. You must use + * ccnxValidationFacadeV1_HasCryptoSuite() to determine if there is a supported crypto suite. + * + * An unsupported crypto suite's entire TLV container is put in the CustomField section of + * the dictionary and you can retrieve it from there if you know the type or iterate the list. + * + * @param [in] message An allocated dictionary + * + * @return value The crypto suite + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * if (ccnxValidationFacadeV1_HasCryptoSuite(dictionary)) { + * PARCCryptoSuite suite = ccnxValidationFacadeV1_GetCryptoSuite(dictionary); + * // process the validation alg + * } + * } + * @endcode + */ +PARCCryptoSuite ccnxValidationFacadeV1_GetCryptoSuite(const CCNxTlvDictionary *message); + +/** + * Determines if the packet specified a signing time + * + * @param [in] message An allocated dictionary + * + * @retval true There is a signing time in the validation algorithm + * @retval false There is not a signing time + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * if (ccnxValidationFacadeV1_HasSigningTime(dictionary)) { + * uint64_t signingTime = ccnxValidationFacadeV1_GetSigningTime(dictionary); + * // process the signing time + * } + * } + * @endcode + */ +bool ccnxValidationFacadeV1_HasSigningTime(const CCNxTlvDictionary *message); + +/** + * Retruns the Validation Algorithm specified in the packet + * + * If the packet has a Signing Time in the Validation Algorithm, return that value. If + * it is not, function all assert an error. You must use + * ccnxValidationFacadeV1_HasSigningTime() to determine if there is a + * signing time. + * + * The signing time is UTC milli-seconds since the epoch. + * + * @param [in] message An allocated dictionary + * + * @return value The signing time in UTC milli-seconds since the epoch. + * + * Example: + * @code + * { + * PARCBuffer *wireFormat = // packet received from the network + * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat); + * if (ccnxValidationFacadeV1_HasSigningTime(dictionary)) { + * uint64_t signingTime = ccnxValidationFacadeV1_GetSigningTime(dictionary); + * // process the signing time + * } + * } + * @endcode + */ +uint64_t ccnxValidationFacadeV1_GetSigningTime(const CCNxTlvDictionary *message); + +// =========================================================== +// Setters + +/** + * Sets the KeyId attribute of the dictionary + * + * The KeyId is a mandatory field for validation algorithms that use a key, such + * as HMAC or RSA or ECC. + * + * Normally, one uses a function in the ccnxValidation algoirthm to set this value + * such as bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid). + * + * @param [in] message The dictionary to set the value in + * @param [in] keyid The encoded value of the keyid + * + * @retval true Value set in the dictionary + * @retval false Error, likely the value was already set + * + * Example: + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL); + * ccnxName_Release(&name); + * + * PARCBuffer *secretKey = parcBuffer_Wrap("password", 8, 0, 8); + * PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey); + * + * PARCKeyId *keyid = parcSigner_CreateKeyId(signer); + * const PARCBuffer *keyIdBytes = parcKeyId_GetKeyId(keyid); + * ccnxValidationFacadeV1_SetKeyId(object, keyIdBytes); + * parcKeyId_Release(&keyid); + * + * // continue with signer and dictionary + * } + * @endcode + */ +bool ccnxValidationFacadeV1_SetKeyId(CCNxTlvDictionary *message, const PARCBuffer *keyid); + + +/** + * Stores the KeyLocator in the standard Dictionary places for use by the standard Getters + * + * If the Validator does not need any special handing of a KeyLocator, this function + * will store the keylocator in the default dictionary entries for use by the standard getters. + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxValidationFacadeV1_SetKeyLocator(CCNxTlvDictionary *message, CCNxKeyLocator *keyLocator); + +/** + * Stores the KeyName in the standard Dictionary places for use by the standard Getters + * + * Stores the fields from the Link in the dictionary. + * + * @param [in] message The message to update + * @param [in] keyNameLink The link to put in the dictionary + * + * @retval true Values successfully added to dictionary + * @retval false An error (likely a duplicate value) + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxValidationFacadeV1_SetKeyName(CCNxTlvDictionary *message, const CCNxLink *keyNameLink); + +/** + * Embeds the DER encoded public key in the Validation Algorithm + * + * If this field is not set, the public key will not be placed in the + * validation algorithm. + * + * @param [in] message The message to update + * @param [in] derEncodedKey The DER encoded public key to put in the dictionary + * + * @retval true Value successfully added to dictionary + * @retval false An error (likely a duplicate value) + * + * Example: + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL); + * ccnxName_Release(&name); + * + * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("keystore.p12", "password", PARCCryptoHashType_SHA256)); + * + * PARCBuffer *publicKey = parcSigner_GetDEREncodedPublicKey(signer); + * + * ccnxValidationFacadeV1_SetPublicKey(object, publicKey); + * + * // continue with signer and dictionary + * } * @endcode + */ +bool ccnxValidationFacadeV1_SetPublicKey(CCNxTlvDictionary *message, const PARCBuffer *derEncodedKey); + +/** + * Embeds the DER encoded public key in the Validation Algorithm + * + * If this field is not set, the public key will not be placed in the + * validation algorithm. + * + * @param [in] message The message to update + * @param [in] derEncodedCertificate The DER encoded public key to put in the dictionary + * + * @retval true Value successfully added to dictionary + * @retval false An error (likely a duplicate value) + * + * Example: + * @code + * { + * CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL); + * ccnxName_Release(&name); + * + * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("keystore.p12", "password", PARCCryptoHashType_SHA256)); + * + * PARCBuffer *cert = parcSigner_GetDEREncodedCertificate(signer); + * + * ccnxValidationFacadeV1_SetPublicKey(object, cert); + * + * // continue with signer and dictionary + * } * @endcode + */ +bool ccnxValidationFacadeV1_SetCertificate(CCNxTlvDictionary *message, const PARCBuffer *derEncodedCertificate); + +/** + * Sets the crypto suite in the dictionary + * + * It is not necessary to set the crypto suite if the packet is encoded with a Signer, + * as the crypto suite will be derived from the signer. + * + * Normally, one uses a function in the ccnxValidation algoirthm to set this value + * such as bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid). + * + * @param [in] message The message to update + * @param [in] suite The cryptosuite value to set in the packet + * + * @retval true The crypto suite was set + * @retval false The crypto suite was not set (not supported by V1 or other error) + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxValidationFacadeV1_SetCryptoSuite(CCNxTlvDictionary *message, PARCCryptoSuite suite); + +/** + * Sets the signing time in the dictionary + * + * The signing time represents when the signature is created. It is sometimes used for + * replay attack prevention. It is the UTC time in milli-seconds since the epoch (i.e. a posix time). + * + * If the signing time is not specified in the dictionary, it will be automatically created + * based on the system clock when the signature is generated (this assumes the system clock + * and timezone are correctly set). + * + * @param [in] message The message to update + * @param [in] signingTime UTC time since the epoch in milli-seconds + * + * @retval true The value was set + * @retval false The value was not set (likely a duplicate value) + * + * Example: + * @code + * @endcode + */ +bool ccnxValidationFacadeV1_SetSigningTime(CCNxTlvDictionary *message, uint64_t signingTime); + +/** + * Saves the validation payload in the dictionary + * + * The validation payload is the output of the validation algorithm, i.e. + * the 32-bit CRC32C checksum or the RSA signature. Usually the Codec is setting this + * value after it has generated the wire format. If this value is set prior to encoding, + * this value will be used regardless if it is correct or not. + * + * You can only save the payload once per dictionary. + * + * @param [in] message The message to update + * @param [in] validationPayload The payload to put in the packet + * + * @return true Payload saved + * @return false Payload was already set or other error + * + * Example: + * @code + * { + * PARCSignature *signature = ccnxCodecTlvEncoder_ComputeSignature(encoder); + * PARCBuffer *sigbits = parcSignature_GetSignature(signature); + * + * // this creates its own reference to sigbits + * ccnxValidationFacadeV1_SetPayload(packetDictionary, sigbits); + * + * parcSignature_Release(&signature); + * parcBuffer_Release(&sigbits); + * } + * @endcode + */ +bool ccnxValidationFacadeV1_SetPayload(CCNxTlvDictionary *message, const PARCBuffer *validationPayload); + +#endif // libccnx_ccnx_ValidationFacadeV1_h 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, +}; diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h new file mode 100755 index 00000000..cd888062 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h @@ -0,0 +1,42 @@ +/* + * 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 ccnx_WireFormatFacadeV1.h + * @ingroup Utility + * + * A WireFormat facade will set/get the wire format representation of a message from the + * dictionary. + * + * One may also create a message dictionary only with a wire format, not specifying the actual message type. + * This occurs mostly at the lowest layer that receives a network buffer and does not yet know what sort of message it holds. + * + * This facade is used by the Forwarder Connector to create the original dictionary + * at the bottom of the stack on receive. It is also used by the Codec component to set + * the wireformat to encode a packet. + * + * If an application has a pre-encoded packet, it can create an empty dictionary and set the wire format + * then send that down the stack. + * + */ +#ifndef libccnx_ccnx_WireFormatFacadeV1_h +#define libccnx_ccnx_WireFormatFacadeV1_h + + +#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h> + +extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation; +#endif // libccnx_ccnx_WireFormatFacadeV1_h diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c new file mode 100755 index 00000000..bb698eb4 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c @@ -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. + */ + +/** + */ + +#include <config.h> + +#include <LongBow/runtime.h> + +#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h> + + +CCNxWireFormatMessageInterface * +ccnxWireFormatMessageInterface_GetInterface(const CCNxTlvDictionary *dictionary) +{ + CCNxWireFormatMessageInterface *impl = NULL; + + int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary); + + switch (schemaVersion) { + case CCNxTlvDictionary_SchemaVersion_V1: + impl = &CCNxWireFormatFacadeV1_Implementation; + break; + default: + trapUnexpectedState("Unknown SchemaVersion encountered in ccnxWireFormatMessageInterface_GetInterface()"); + break; + } + + // We do not set the implementation pointer in the dictionary here. That is only done when accessing the dictionary + // as a CCNxContentObject, CCNxInterest, CCNxInterestReturn, or CCNxControlMessage. + + return impl; +} diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h new file mode 100755 index 00000000..2efc2194 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h @@ -0,0 +1,121 @@ +/* + * 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. + */ + +/** + * @brief The definition of the interface used to call into a CCNxWireFormatFacade implementation. + * + */ + +#ifndef CCNx_Common_ccnx_internal_WireFormatMessageInterface_h +#define CCNx_Common_ccnx_internal_WireFormatMessageInterface_h + +#include <ccnx/common/internal/ccnx_TlvDictionary.h> + +typedef struct ccnx_wireformatmessage_interface { + char *description; // A human-readable label for this implementation + + /** @see ccnxWireFormatMessage_Create */ + CCNxTlvDictionary *(*create)(const PARCBuffer * wireFormat); + + /** @see ccnxWireFormatMessage_FromInterestPacketType */ + CCNxTlvDictionary *(*fromInterestPacketType)(const PARCBuffer * wireFormat); + + /** @see ccnxWireFormatMessage_FromInterestPacketTypeIoVec */ + CCNxTlvDictionary *(*fromInterestPacketTypeIoVec)(const CCNxCodecNetworkBufferIoVec * vec); + + /** @see ccnxWireFormatMessage_FromContentObjectPacketType */ + CCNxTlvDictionary *(*fromContentObjectPacketType)(const PARCBuffer * wireFormat); + + /** @see ccnxWireFormatMessage_FromControlPacketType */ + CCNxTlvDictionary *(*fromControlPacketType)(const PARCBuffer * wireFormat); + + /** @see ccnxWireFormatMessage_GetWireFormatBuffer */ + PARCBuffer *(*getWireFormatBuffer)(const CCNxTlvDictionary * dictionary); + + /** @see ccnxWireFormatMessage_GetIoVec */ + CCNxCodecNetworkBufferIoVec *(*getIoVec)(const CCNxTlvDictionary * dictionary); + + /** @see ccnxWireFormatMessage_PutWireFormatBuffer */ + bool (*putWireFormatBuffer)(CCNxTlvDictionary *dictionary, PARCBuffer *buffer); + + /** @see ccnxWireFormatMessage_PutIoVec */ + bool (*putIoVec)(CCNxTlvDictionary *dictionary, CCNxCodecNetworkBufferIoVec *vec); + + /** @see ccnxWireFormatMessage_WriteToFile */ + void (*writeToFile)(const CCNxTlvDictionary *dictionary, const char *filename); + + /** @see ccnxWireFormatMessage_SetProtectedRegionStart */ + bool (*setProtectedRegionStart)(CCNxTlvDictionary *dictionary, size_t startPosition); + + /** @see ccnxWireFormatMessage_SetProtectedRegionLength */ + bool (*setProtectedRegionLength)(CCNxTlvDictionary *dictionary, size_t length); + + /** @see ccnxWireFormatMessage_SetContentObjectHashRegionStart */ + bool (*setContentObjectHashRegionStart)(CCNxTlvDictionary *dictionary, size_t startPosition); + + /** @see ccnxWireFormatMessage_SetContentObjectHashRegionLength */ + bool (*setContentObjectHashRegionLength)(CCNxTlvDictionary *dictionary, size_t length); + + /** @see ccnxWireFormatMessage_HashProtectedRegion */ + PARCCryptoHash *(*hashProtectedRegion)(const CCNxTlvDictionary * dictionary, PARCCryptoHasher * hasher); + + /** @see ccnxWireFormatMessage_SetHopLimit */ + bool (*setHopLimit)(CCNxTlvDictionary *dictionary, uint32_t hopLimit); + + /** @see ccnxWireFormatMessage_AssertValid*/ + void (*assertValid)(const CCNxTlvDictionary *dictionary); + + /** @see ccnxWireFormatMessage_CreateContentObjectHash */ + PARCCryptoHash *(*computeContentObjectHash)(CCNxTlvDictionary * dictionary); + + /** @see ccnxWireFormatMessage_ConvertInterestToInterestReturn */ + bool (*convertInterestToInterestReturn)(CCNxTlvDictionary *dictionary, uint8_t returnCode); +} CCNxWireFormatMessageInterface; + +/** + * The SchemaV0 WireFormatMessage implementaton + */ +extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV0_Implementation; + +/** + * The SchemaV1 WireFormatMessage implementaton + */ +extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation; + +/** + * Given a CCNxTlvDictionary representing a CCNxWireFormatMessage, return the address of the CCNxWireFormatMessageInterface + * instance that should be used to access the WireFormatMessage. + * + * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterestReturn. + * @return the address of the `CCNxWireFormatMessageInterface` instance that should be used to access the CCNxWireFormatMessage. + * + * Example: + * @code + * { + * + * CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(schemaVersion, wireFormatBuffer); + * + * //V1 test + * if (ccnxWireFormatMessageInterface_GetInterface(interestReturn) == &CCNxWireFormatFacadeV1_Implementation) { + * printf("Using a V1 CCNxWireFormatFacadeV1_Implementation \n"); + * } + * + * ... + * + * ccnxWireFormatMessage_Release(&message); + * } * @endcode + */ +CCNxWireFormatMessageInterface *ccnxWireFormatMessageInterface_GetInterface(const CCNxTlvDictionary *contentDictionary); +#endif diff --git a/libccnx-common/ccnx/common/internal/test/.gitignore b/libccnx-common/ccnx/common/internal/test/.gitignore new file mode 100644 index 00000000..d8148318 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/.gitignore @@ -0,0 +1,18 @@ +test_ccnx_ChunkingFacadeV0 +test_ccnx_ChunkingFacadeV1 +test_ccnx_ContentObjectFacadeV0 +test_ccnx_ContentObjectFacadeV1 +test_ccnx_ContentObjectInterface +test_ccnx_ControlFacade +test_ccnx_InterestFacadeV0 +test_ccnx_InterestFacadeV1 +test_ccnx_InterestInterface +test_ccnx_InterestReturnInterface +test_ccnx_Tlv +test_ccnx_TlvDictionary +test_ccnx_TlvEncodingBuffer +test_ccnx_TlvError +test_ccnx_ValidationFacadeV0 +test_ccnx_ValidationFacadeV1 +test_ccnx_WireFormatFacadeV0 +test_ccnx_WireFormatFacadeV1 diff --git a/libccnx-common/ccnx/common/internal/test/CMakeLists.txt b/libccnx-common/ccnx/common/internal/test/CMakeLists.txt new file mode 100644 index 00000000..900ba031 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/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") + +set(TestsExpectedToPass + test_ccnx_ChunkingFacadeV1 + test_ccnx_ContentObjectFacadeV1 + test_ccnx_ContentObjectInterface + test_ccnx_InterestFacadeV1 + test_ccnx_InterestInterface + test_ccnx_InterestReturnFacadeV1 + test_ccnx_InterestReturnInterface + test_ccnx_ManifestFacadeV1 + test_ccnx_ManifestInterface + test_ccnx_TlvDictionary + test_ccnx_ValidationFacadeV1 + test_ccnx_WireFormatFacadeV1 +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade Binary files differnew file mode 100755 index 00000000..0894fcbd --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c new file mode 100755 index 00000000..6f14cf47 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c @@ -0,0 +1,261 @@ +/* + * 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 "../ccnx_ChunkingFacadeV1.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> +#include <inttypes.h> + +#include <ccnx/common/ccnx_ContentObject.h> +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_PayloadType.h> + +#include <ccnx/common/internal/ccnx_ContentObjectInterface.h> + +typedef struct test_data { + CCNxName *name; + CCNxTlvDictionary *contentObjectV1; + CCNxTlvDictionary *contentObjectVFF; + + CCNxTlvDictionary *interest; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->name = ccnxName_CreateFromCString("lci:/foo/bar/v1"); + + data->contentObjectV1 = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + data->name, + CCNxPayloadType_DATA, NULL); + + data->contentObjectVFF = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + ccnxTlvDictionary_SetMessageType_ContentObject(data->contentObjectVFF, 0xFF); + + data->interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + data->name, 5000, NULL, NULL, 100); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxName_Release(&data->name); + ccnxTlvDictionary_Release(&data->contentObjectV1); + ccnxTlvDictionary_Release(&data->contentObjectVFF); + ccnxTlvDictionary_Release(&data->interest); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_ChunkingFacade) +{ + // 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(ccnx_ChunkingFacade) +{ + 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_ChunkingFacade) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_NotContentObject); + + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_With); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_Without); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_InvalidVersion); + + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_NotContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_With); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_Without); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_InvalidVersion); + + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_NotContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_InvalidVersion); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _commonTeardown(data); + + 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_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_NotContentObject, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxChunkingFacadeV1_GetEndChunkNumber(data->interest); +} + +LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_With) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint64_t endChunkNumber = 5; + + ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, endChunkNumber); + uint64_t test = ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectV1); + assertTrue(test == endChunkNumber, "wrong value, got %" PRIu64 " expected %" PRIu64 "", test, endChunkNumber) + { + ccnxTlvDictionary_Display(data->contentObjectV1, 3); + } +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_Without, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectV1); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectVFF); +} + +// ====================================================================================== + + +LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_NotContentObject) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->interest); + assertFalse(success, "An Interest should always return FALSE for EndChunkNumber"); +} + +LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_With) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, 5); + bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectV1); + assertTrue(success, "Content Object with EndChunkNumber returned false") + { + ccnxTlvDictionary_Display(data->contentObjectV1, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_Without) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectV1); + assertFalse(success, "Content Object without EndChunkNumber returned true") + { + ccnxTlvDictionary_Display(data->contentObjectV1, 3); + } +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_HasEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectVFF); +} + +// ====================================================================================== + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_SetEndChunkNumber_NotContentObject, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint64_t endChunkNumber = 7; + ccnxChunkingFacadeV1_SetEndChunkNumber(data->interest, endChunkNumber); +} + + +LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_V1) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint64_t endChunkNumber = 7; + bool success = ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, endChunkNumber); + + assertTrue(success, "Setting EndChunkNumber failed") + { + ccnxTlvDictionary_Display(data->contentObjectV1, 3); + } +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_SetEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectVFF, 7); +} + +// ====================================================================================== + +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(ccnx_ChunkingFacade); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade Binary files differnew file mode 100755 index 00000000..073ccae4 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c new file mode 100644 index 00000000..b3c6b343 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c @@ -0,0 +1,377 @@ +/* + * 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 "../ccnx_ContentObjectFacadeV1.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> +#include <inttypes.h> + +typedef struct test_data { + CCNxName *name; + CCNxPayloadType payloadType; + PARCBuffer *payload; + + // a V1 dictionary but with no values set + CCNxTlvDictionary *contentObjectV1Empty; + + // a V1 nameless Content Object + CCNxTlvDictionary *contentObjectV1Nameless; + + // a valid V1 Content Object + CCNxTlvDictionary *contentObjectV1; + CCNxTlvDictionary *contentObjectVFF; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->name = ccnxName_CreateFromCString("lci:/foo/bar"); + data->payloadType = CCNxPayloadType_DATA; + + data->payload = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 7, (uint8_t *) "payload")); + + data->contentObjectV1Empty = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + data->contentObjectV1 = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name, data->payloadType, + data->payload); + data->contentObjectV1Nameless = _ccnxContentObjectFacadeV1_CreateWithPayload(data->payloadType, data->payload); + + data->contentObjectVFF = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_ContentObject(data->contentObjectVFF, 0xFF); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxName_Release(&data->name); + parcBuffer_Release(&data->payload); + + ccnxTlvDictionary_Release(&data->contentObjectV1Empty); + ccnxTlvDictionary_Release(&data->contentObjectV1); + ccnxTlvDictionary_Release(&data->contentObjectV1Nameless); + ccnxTlvDictionary_Release(&data->contentObjectVFF); + parcMemory_Deallocate((void **) &data); +} + + +LONGBOW_TEST_RUNNER(ccnx_ContentObjectFacade) +{ + // 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(ImplInterface); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObjectFacade) +{ + 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_ContentObjectFacade) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(ImplInterface) +{ + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Init); + + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetName); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayload); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload_Link); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType_Unset); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetExpiryTime); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetExpiryTime); + + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetSignature); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetKeyId); + + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_ToString); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Display); + LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Equals); +} + +LONGBOW_TEST_FIXTURE_SETUP(ImplInterface) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ImplInterface) +{ + _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(ImplInterface, ccnxContentObjectFacadeV1_Init) +{ + CCNxContentObjectInterface *impl = &CCNxContentObjectFacadeV1_Implementation; + assertNotNull(impl->createWithNameAndPayload, "Expected CreateWithNameAndPayload to be set"); + assertNotNull(impl->createWithPayload, "Expected CreateWithPayload to be set"); + + assertNotNull(impl->getName, "Expected GetName to be set"); + assertNotNull(impl->setSignature, "Expected SetSignature to be set"); + assertNotNull(impl->getKeyId, "Expected GetKeyID to be set"); + assertNotNull(impl->getPayload, "Expected GetPayload to be set"); + assertNotNull(impl->getPayloadType, "Expected GetPayloadType to be set"); + + assertNotNull(impl->hasFinalChunkNumber, "Expected HasFinalChunkNumber to be set"); + assertNotNull(impl->getFinalChunkNumber, "Expected GetFinalChunkNumber to be set"); + assertNotNull(impl->setFinalChunkNumber, "Expected SetFinalChunkNumber to be set"); + + assertNotNull(impl->hasExpiryTime, "Expected HasExpiryTime to be set"); + assertNotNull(impl->getExpiryTime, "Expected GetExpiryTime to be set"); + assertNotNull(impl->setExpiryTime, "Expected SetExpiryTime to be set"); + + assertNotNull(impl->toString, "Expected ToString to be set"); + assertNotNull(impl->display, "Expected Display to be set"); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = _ccnxContentObjectFacadeV1_GetName(data->contentObjectV1); + assertTrue(ccnxName_Equals(test, data->name), "Names do not match") + { + ccnxName_Display(test, 0); + ccnxName_Display(data->name, 0); + } + test = _ccnxContentObjectFacadeV1_GetName(data->contentObjectV1Nameless); + assertNull(test, "A nameless Content Object has no name."); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *newPayload = parcBuffer_WrapCString("this is a new payload"); + + // Shouldn't be able to set it on an already initialized ContentObject. + // (Though this may change...) + assertFalse(_ccnxContentObjectFacadeV1_SetPayload(data->contentObjectV1, CCNxPayloadType_DATA, newPayload), + "Expected to not be able to re-assign a payload on an already initialized ContentObject"); + + CCNxTlvDictionary *contentObject = + _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name, + CCNxPayloadType_DATA, + NULL); + + + bool status = _ccnxContentObjectFacadeV1_SetPayload(contentObject, CCNxPayloadType_KEY, newPayload); + assertTrue(status, "Expected to be able to set the buffer"); + + PARCBuffer *testPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObject); + assertTrue(parcBuffer_Equals(newPayload, testPayload), "payloads do not match") + { + parcBuffer_Display(newPayload, 0); + parcBuffer_Display(data->payload, 0); + } + + CCNxPayloadType testType = _ccnxContentObjectFacadeV1_GetPayloadType(contentObject); + assertTrue(testType == CCNxPayloadType_KEY, "Expected type KEY"); + + parcBuffer_Release(&newPayload); + ccnxTlvDictionary_Release(&contentObject); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload_Link) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *payload = parcBuffer_WrapCString("this is a payload"); + + CCNxTlvDictionary *contentObject = + _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name, + CCNxPayloadType_LINK, + payload); + + PARCBuffer *testPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObject); + assertTrue(parcBuffer_Equals(payload, testPayload), "payloads do not match") + { + parcBuffer_Display(payload, 0); + parcBuffer_Display(testPayload, 0); + } + + CCNxPayloadType testType = _ccnxContentObjectFacadeV1_GetPayloadType(contentObject); + assertTrue(testType == CCNxPayloadType_LINK, "Expected type LINK"); + + parcBuffer_Release(&payload); + ccnxTlvDictionary_Release(&contentObject); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = _ccnxContentObjectFacadeV1_GetPayload(data->contentObjectV1); + assertTrue(parcBuffer_Equals(test, data->payload), "payloads do not match") + { + parcBuffer_Display(test, 0); + parcBuffer_Display(data->payload, 0); + } +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxPayloadType test = _ccnxContentObjectFacadeV1_GetPayloadType(data->contentObjectV1); + assertTrue(test == data->payloadType, "payloads do not match, got %d expected %d", test, data->payloadType) + { + ccnxTlvDictionary_Display(data->contentObjectV1, 0); + } +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType_Unset) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxPayloadType test = _ccnxContentObjectFacadeV1_GetPayloadType(data->contentObjectV1Empty); + assertTrue(test == CCNxPayloadType_DATA, "payloads do not match, got %d expected %d", test, CCNxPayloadType_DATA) + { + ccnxTlvDictionary_Display(data->contentObjectV1, 0); + } +} + +LONGBOW_TEST_CASE_EXPECTS(ImplInterface, ccnxContentObjectFacadeV1_ToString, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _ccnxContentObjectFacadeV1_ToString(data->contentObjectV1); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _ccnxContentObjectFacadeV1_Display(data->contentObjectV1, 0); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Equals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertTrue(_ccnxContentObjectFacadeV1_Equals(data->contentObjectV1, data->contentObjectV1), + "Expected equals to be true"); + assertFalse(_ccnxContentObjectFacadeV1_Equals(data->contentObjectV1, data->contentObjectV1Empty), + "Expected equals to be false"); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetExpiryTime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint64_t truth = 12345; + ccnxTlvDictionary_PutInteger(data->contentObjectV1, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, truth); + + assertTrue(_ccnxContentObjectFacadeV1_HasExpiryTime(data->contentObjectV1), "Expected HasExpiryTime() to return true"); + uint64_t expiryTime = _ccnxContentObjectFacadeV1_GetExpiryTime(data->contentObjectV1); + assertTrue(truth == expiryTime, "times do not match, expected %" PRIu64 ", got %" PRIu64, truth, expiryTime); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetExpiryTime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + uint64_t truth = 12345; + _ccnxContentObjectFacadeV1_SetExpiryTime(data->contentObjectV1, truth); + uint64_t expiryTime = _ccnxContentObjectFacadeV1_GetExpiryTime(data->contentObjectV1); + assertTrue(truth == expiryTime, "times do not match, expected %" PRIu64 ", got %" PRIu64, truth, expiryTime); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetSignature) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/baz"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxTlvDictionary *contentObject = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(name, CCNxPayloadType_DATA, + payload); + + PARCBuffer *keyId = parcBuffer_WrapCString("keyhash"); + char *rawsig = "siggybits"; + PARCBuffer *sigbits = parcBuffer_CreateFromArray((void *) rawsig, strlen(rawsig)); + + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits)); + parcBuffer_Release(&sigbits); + + assertTrue(_ccnxContentObjectFacadeV1_SetSignature(contentObject, keyId, signature, NULL), + "Expected to be able to set the signature"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + parcSignature_Release(&signature); + parcBuffer_Release(&keyId); + ccnxTlvDictionary_Release(&contentObject); +} + +LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetKeyId) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/baz"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxTlvDictionary *contentObject = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(name, CCNxPayloadType_DATA, + payload); + + assertNull(_ccnxContentObjectFacadeV1_GetKeyId(contentObject), "Expect key ID to be NULL"); + + PARCBuffer *testKeyId = parcBuffer_WrapCString("keyhash"); + char *rawsig = "siggybits"; + PARCBuffer *sigbits = parcBuffer_CreateFromArray((void *) rawsig, strlen(rawsig)); + + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits)); + parcBuffer_Release(&sigbits); + + assertTrue(_ccnxContentObjectFacadeV1_SetSignature(contentObject, testKeyId, signature, NULL), + "Expected to be able to set the signature"); + + PARCBuffer *keyId = _ccnxContentObjectFacadeV1_GetKeyId(contentObject); + + assertTrue(parcBuffer_Equals(keyId, testKeyId), "Expect key ID's to be the same"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + parcSignature_Release(&signature); + parcBuffer_Release(&keyId); + ccnxTlvDictionary_Release(&contentObject); +} + +// ====================================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObjectFacade); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c new file mode 100755 index 00000000..65e78bed --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c @@ -0,0 +1,106 @@ +/* + * 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 "../ccnx_ContentObjectInterface.c" + +#include <stdio.h> + +#include <ccnx/common/ccnx_ContentObject.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(ccnx_ContentObjectInterface) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObjectInterface) +{ + 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_ContentObjectInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObjectInterface_GetInterface); +} + +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, ccnxContentObjectInterface_GetInterface) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + + CCNxContentObject *contentObjectV1 = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, + CCNxPayloadType_DATA, + NULL); + + assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation, + "Expected V1 Implementation"); + + // Now unset the pointer and see if it gets derived properly. + ccnxTlvDictionary_SetMessageInterface(contentObjectV1, NULL); + assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation, + "Expected V1 Implementation"); + + + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObjectV1); +} + + +// ====================================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObjectInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c new file mode 100755 index 00000000..477b963d --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c @@ -0,0 +1,334 @@ +/* + * 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 "../ccnx_InterestFacadeV1.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/ccnx_Interest.h> + +typedef struct test_data { + CCNxTlvDictionary *interest; + + CCNxName *name; + PARCBuffer *keyid; + PARCBuffer *contentObjectHash; + PARCBuffer *payload; + + // allocated data + uint8_t keyidArray[32]; + uint8_t contentObjectHashArray[32]; + uint8_t payloadArray[128]; + + uint32_t lifetime; + uint32_t hoplimit; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time"); + + for (int i = 0; i < 32; i++) { + data->keyidArray[i] = i * 7; + data->contentObjectHashArray[i] = i * 11; + } + + for (int i = 0; i < 128; i++) { + data->payloadArray[i] = i * 13; + } + + data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32); + data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32); + data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128); + + data->lifetime = 900; + data->hoplimit = 77; + + data->interest = _ccnxInterestFacadeV1_Create(data->name, + data->lifetime, + data->keyid, + data->contentObjectHash, + data->hoplimit); + + _ccnxInterestFacadeV1_SetPayload(data->interest, data->payload); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxName_Release(&data->name); + parcBuffer_Release(&data->keyid); + parcBuffer_Release(&data->contentObjectHash); + parcBuffer_Release(&data->payload); + ccnxTlvDictionary_Release(&data->interest); + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_InterestFacadeV1) +{ + // 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(Performance); + + 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(ccnx_InterestFacadeV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestFacadeV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ======================================================================================== + +LONGBOW_TEST_FIXTURE(Performance) +{ + LONGBOW_RUN_TEST_CASE(Performance, newfangled); +// LONGBOW_RUN_TEST_CASE(Performance, oldtimey); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + 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(Performance, newfangled) +{ + uint8_t keyidArray[32]; + for (int i = 0; i < 32; i++) { + keyidArray[i] = i; + } + + PARCBuffer *keyid = parcBuffer_Wrap(keyidArray, 32, 0, 32); + CCNxName *name = ccnxName_CreateFromCString("lci:/dark/and/stormy/bits"); + + struct timeval t0, t1; + unsigned trials = 10000; + gettimeofday(&t0, NULL); + for (int i = 0; i < trials; i++) { + CCNxTlvDictionary *interest = _ccnxInterestFacadeV1_Create(name, + CCNxInterestDefault_LifetimeMilliseconds, + keyid, + NULL, + 0x45); + + ccnxTlvDictionary_Release(&interest); + } + gettimeofday(&t1, NULL); + timersub(&t1, &t0, &t1); + double seconds = t1.tv_sec + t1.tv_usec * 1E-6; + printf("\nNewFangled iterations %u seconds %.3f msg/sec %.3f\n", trials, seconds, trials / seconds); + + ccnxName_Release(&name); + parcBuffer_Release(&keyid); +} + + +// ======================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_CreateSimple); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetContentObjectHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetHopLimit); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetInterestLifetime); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetName); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetPayload); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetPublisherPublicKeyDigest); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_AssertValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_Display); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_Equals); +} + +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, ccnxInterestFacadeV1_CreateSimple) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *interest = _ccnxInterestFacadeV1_CreateSimple(data->name); + + CCNxName *test = _ccnxInterestFacadeV1_GetName(interest); + assertTrue(ccnxName_Equals(test, data->name), "Names do not match"); + ccnxTlvDictionary_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetContentObjectHash) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = _ccnxInterestFacadeV1_GetContentObjectHashRestriction(data->interest); + assertTrue(parcBuffer_Equals(test, data->contentObjectHash), "ContentObjectHashes do not match") + { + printf("\ngot : \n"); parcBuffer_Display(test, 3); + printf("\nexpected: \n"); parcBuffer_Display(data->contentObjectHash, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetHopLimit) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + unsigned test = (unsigned) _ccnxInterestFacadeV1_GetHopLimit(data->interest); + assertTrue(test == data->hoplimit, "Wrong hoplimit: got %u expected %u", test, data->hoplimit); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetInterestLifetime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + unsigned test = (unsigned) _ccnxInterestFacadeV1_GetLifetime(data->interest); + assertTrue(test == data->lifetime, "Wrong lifetime: got %u expected %u", test, data->lifetime); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_AssertValid) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _ccnxInterestFacadeV1_Display(data->interest, 4); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + _ccnxInterestFacadeV1_AssertValid(data->interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = _ccnxInterestFacadeV1_GetName(data->interest); + assertTrue(ccnxName_Equals(test, data->name), "Names do not match") + { + printf("\ngot : \n"); ccnxName_Display(test, 3); + printf("\nexpected: \n"); ccnxName_Display(data->name, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetPublisherPublicKeyDigest) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = _ccnxInterestFacadeV1_GetKeyIdRestriction(data->interest); + assertTrue(parcBuffer_Equals(test, data->keyid), "KeyIDs do not match") + { + printf("\ngot : \n"); parcBuffer_Display(test, 3); + printf("\nexpected: \n"); parcBuffer_Display(data->keyid, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetPayload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = _ccnxInterestFacadeV1_GetPayload(data->interest); + assertTrue(parcBuffer_Equals(test, data->payload), "Payloads do not match") + { + printf("\ngot : \n"); parcBuffer_Display(test, 3); + printf("\nexpected: \n"); parcBuffer_Display(data->payload, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_Equals) +{ + CCNxName *name1 = ccnxName_CreateFromCString("lci:/name/1"); + CCNxName *name2 = ccnxName_CreateFromCString("lci:/name/2"); + + CCNxTlvDictionary *x = _ccnxInterestFacadeV1_CreateSimple(name1); // same + CCNxTlvDictionary *y = _ccnxInterestFacadeV1_CreateSimple(name1); // same + CCNxTlvDictionary *z = _ccnxInterestFacadeV1_CreateSimple(name1); // same + + CCNxTlvDictionary *diff = _ccnxInterestFacadeV1_CreateSimple(name2); // different + + assertEqualsContract(_ccnxInterestFacadeV1_Equals, x, y, z, diff); + + ccnxTlvDictionary_Release(&x); + ccnxTlvDictionary_Release(&y); + ccnxTlvDictionary_Release(&z); + ccnxTlvDictionary_Release(&diff); + + ccnxName_Release(&name1); + ccnxName_Release(&name2); +} + + +// ======================================================================================== + +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(ccnx_InterestFacadeV1); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c new file mode 100755 index 00000000..67bde1f5 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c @@ -0,0 +1,107 @@ +/* + * 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 <config.h> +#include <LongBow/unit-test.h> + +#include "../ccnx_InterestInterface.c" + +#include <stdio.h> + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/internal/ccnx_InterestDefault.h> + +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(ccnx_InterestInterface) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestInterface) +{ + 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_InterestInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestInterface_GetInterface); +} + +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, ccnxInterestInterface_GetInterface) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + + CCNxInterest *interestV1 = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, + CCNxInterestDefault_LifetimeMilliseconds, + NULL, + NULL, + CCNxInterestDefault_HopLimit); + + CCNxInterestInterface *interface = ccnxInterestInterface_GetInterface(interestV1); + assertTrue(interface == &CCNxInterestFacadeV1_Implementation, "Expected V1 Implementation"); + + ccnxName_Release(&name); + ccnxInterest_Release(&interestV1); +} + + +// ====================================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c new file mode 100755 index 00000000..1372a750 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c @@ -0,0 +1,168 @@ +/* + * 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 "../ccnx_InterestReturnFacadeV1.c" +#include "../ccnx_InterestFacadeV1.h" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_InterestReturn.h> +#include <ccnx/common/ccnx_PayloadType.h> + +typedef struct test_data { + CCNxTlvDictionary *interest; + + CCNxName *name; + PARCBuffer *keyid; + PARCBuffer *contentObjectHash; + PARCBuffer *payload; + + // allocated data + uint8_t keyidArray[32]; + uint8_t contentObjectHashArray[32]; + uint8_t payloadArray[128]; + + uint32_t lifetime; + uint32_t hoplimit; + CCNxPayloadType payloadType; +} TestData; + + +LONGBOW_TEST_RUNNER(ccnx_InterestReturnFacadeV1) +{ + // 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(ccnx_InterestReturnFacadeV1) +{ + 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_InterestReturnFacadeV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ======================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnFacadeV1_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnFacadeV1_GetReturnCode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%lu) returned NULL", sizeof(TestData)); + data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time"); + + for (int i = 0; i < 32; i++) { + data->keyidArray[i] = i * 7; + data->contentObjectHashArray[i] = i * 11; + } + + for (int i = 0; i < 128; i++) { + data->payloadArray[i] = i * 13; + } + + data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32); + data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32); + data->payloadType = CCNxPayloadType_DATA; + data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128); + + data->lifetime = 900; + data->hoplimit = 77; + + data->interest = ccnxInterest_Create(data->name, + data->lifetime, + data->keyid, + data->contentObjectHash); + + ccnxInterest_SetPayload(data->interest, data->payload); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxName_Release(&data->name); + parcBuffer_Release(&data->keyid); + parcBuffer_Release(&data->contentObjectHash); + parcBuffer_Release(&data->payload); + ccnxTlvDictionary_Release(&data->interest); + + parcMemory_Deallocate((void **) &data); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_TEARDOWN_FAILED; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnFacadeV1_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxTlvDictionary *interestReturn = + _ccnxInterestReturnFacadeV1_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + assertNotNull(interestReturn, "Expect non-NULL interestReturn"); + _ccnxInterestReturnFacadeV1_AssertValid(interestReturn); + + CCNxInterestReturn_ReturnCode code = _ccnxInterestReturnFacadeV1_GetReturnCode(interestReturn); + assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code"); + ccnxTlvDictionary_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnFacadeV1_GetReturnCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxTlvDictionary *interestReturn = + _ccnxInterestReturnFacadeV1_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + _ccnxInterestReturnFacadeV1_AssertValid(interestReturn); + + CCNxInterestReturn_ReturnCode code = + _ccnxInterestReturnFacadeV1_GetReturnCode(interestReturn); + + assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code"); + ccnxTlvDictionary_Release(&interestReturn); +} + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnFacadeV1); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c new file mode 100755 index 00000000..a22ab4e9 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c @@ -0,0 +1,112 @@ +/* + * 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 "../ccnx_InterestReturnInterface.c" + +#include <ccnx/common/ccnx_InterestReturn.h> +#include <ccnx/common/internal/ccnx_InterestDefault.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <stdio.h> + +LONGBOW_TEST_RUNNER(ccnx_InterestReturnInterface) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestReturnInterface) +{ + 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_InterestReturnInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnInterface_GetImplementation); +} + +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, ccnxInterestReturnInterface_GetImplementation) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + + CCNxInterest *interestV1 = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, + CCNxInterestDefault_LifetimeMilliseconds, + NULL, + NULL, + CCNxInterestDefault_HopLimit); + ccnxName_Release(&name); + + CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interestV1, CCNxInterestReturn_ReturnCode_Congestion); + + assertTrue(ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation, + "Expected V1 Implementation"); + + // Now unset the pointer and see if it gets derived properly. + ccnxTlvDictionary_SetMessageInterface(interestReturn, NULL); + + assertTrue(ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation, + "Expected V1 Implementation"); + + ccnxInterestReturn_Release(&interestReturn); + ccnxInterest_Release(&interestV1); +} + + +// ====================================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c new file mode 100644 index 00000000..253b8e5a --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c @@ -0,0 +1,223 @@ +/* + * 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 "../ccnx_ManifestFacadeV1.c" +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_Memory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/ccnx_Manifest.h> + +typedef struct test_data { + CCNxTlvDictionary *manifest; + + CCNxName *name; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time"); + data->manifest = _ccnxManifestFacadeV1_Create(data->name); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxName_Release(&data->name); + ccnxTlvDictionary_Release(&data->manifest); + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_ManifestFacadeV1) +{ + // 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(ccnx_ManifestFacadeV1) +{ + 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_ManifestFacadeV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ======================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_GetName); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_AddHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_GetHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_Equals); +} + +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, ccnxManifestFacadeV1_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name); + + const CCNxName *test = _ccnxManifestFacadeV1_GetName(manifest); + assertTrue(ccnxName_Equals(test, data->name), "Names do not match"); + ccnxTlvDictionary_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_AddHashGroup) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name); + + int actual = 0; + int numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest); + assertTrue(numberOfGroups == actual, "Expected %d, got %d", actual, numberOfGroups); + + CCNxManifestHashGroup *hashGroup = ccnxManifestHashGroup_Create(); + _ccnxManifestFacadeV1_AddHashGroup(manifest, hashGroup); + actual++; + numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest); + + assertTrue(numberOfGroups == actual, "Expected %d, got %d", actual, numberOfGroups); + + ccnxManifestHashGroup_Release(&hashGroup); + ccnxTlvDictionary_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetHashGroup) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name); + + CCNxManifestHashGroup *hashGroup = ccnxManifestHashGroup_Create(); + _ccnxManifestFacadeV1_AddHashGroup(manifest, hashGroup); + + CCNxManifestHashGroup *firstGroup = _ccnxManifestFacadeV1_GetHashGroup(manifest, 0); + assertTrue(ccnxManifestHashGroup_Equals(hashGroup, firstGroup), "Expected the HashGroups to be equal"); + + ccnxManifestHashGroup_Release(&hashGroup); + ccnxManifestHashGroup_Release(&firstGroup); + ccnxTlvDictionary_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetNumberOfHashGroups) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name); + + size_t numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest); + assertTrue(numberOfGroups == 1, "Expected 1 group, got %zu", numberOfGroups); + ccnxTlvDictionary_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + const CCNxName *test = _ccnxManifestFacadeV1_GetName(data->manifest); + assertTrue(ccnxName_Equals(test, data->name), "Names do not match") + { + printf("\ngot : \n"); ccnxName_Display(test, 3); + printf("\nexpected: \n"); ccnxName_Display(data->name, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_Equals) +{ + CCNxName *name1 = ccnxName_CreateFromCString("lci:/name/1"); + CCNxName *name2 = ccnxName_CreateFromCString("lci:/name/2"); + + CCNxTlvDictionary *x = _ccnxManifestFacadeV1_Create(name1); + CCNxTlvDictionary *y = _ccnxManifestFacadeV1_Create(name1); + CCNxTlvDictionary *z = _ccnxManifestFacadeV1_Create(name1); + + CCNxTlvDictionary *diff = _ccnxManifestFacadeV1_Create(name2); + + assertEqualsContract(_ccnxManifestFacadeV1_Equals, x, y, z, diff, NULL); + + ccnxTlvDictionary_Release(&x); + ccnxTlvDictionary_Release(&y); + ccnxTlvDictionary_Release(&z); + ccnxTlvDictionary_Release(&diff); + + ccnxName_Release(&name1); + ccnxName_Release(&name2); +} + +// ======================================================================================== + +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(ccnx_ManifestFacadeV1); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c new file mode 100755 index 00000000..42ce095f --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c @@ -0,0 +1,100 @@ +/* + * 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 "../ccnx_ManifestInterface.c" + +#include <ccnx/common/ccnx_Manifest.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <stdio.h> + +LONGBOW_TEST_RUNNER(ccnx_ManifestInterface) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ManifestInterface) +{ + 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_ManifestInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestInterface_GetImplementation); +} + +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, ccnxManifestInterface_GetImplementation) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + + CCNxManifest *manifestV1 = ccnxManifest_Create(name); + ccnxName_Release(&name); + + assertTrue(ccnxManifestInterface_GetInterface(manifestV1) == &CCNxManifestFacadeV1_Interface, "Expected V1 Implementation"); + + // Now unset the pointer and see if it gets derived properly. + ccnxTlvDictionary_SetMessageInterface(manifestV1, NULL); + + assertTrue(ccnxManifestInterface_GetInterface(manifestV1) == &CCNxManifestFacadeV1_Interface, "Expected V1 Implementation"); + + ccnxManifest_Release(&manifestV1); +} + + +// ====================================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ManifestInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c new file mode 100755 index 00000000..51936d96 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c @@ -0,0 +1,1142 @@ +/* + * 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 "../ccnx_TlvDictionary.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <ccnx/common/internal/ccnx_ContentObjectInterface.h> +#include <ccnx/common/internal/ccnx_InterestInterface.h> + +#include <LongBow/unit-test.h> + +typedef struct test_data { + CCNxTlvDictionary *dictionary; + size_t fastArraySize; + size_t listSize; +} TestData; + +typedef enum { + SchemaFree = 0, + SchemaBuffer = 1, + SchemaInteger = 2, + SchemaIoVec = 3, + SchemaJson = 4, + SchemaName = 5, + SchemaEnd = 6, +} TestSchema; + +static CCNxCodecNetworkBufferIoVec * +createIoVec(void) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + ccnxCodecNetworkBuffer_Release(&netbuff); + return vec; +} + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->fastArraySize = SchemaEnd + 2; + data->listSize = SchemaEnd + 10; + data->dictionary = ccnxTlvDictionary_Create(data->fastArraySize, data->listSize); + + // populate the know test vectors + PARCBuffer *buffer = parcBuffer_Allocate(5); + ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaBuffer, buffer); + parcBuffer_Release(&buffer); + + ccnxTlvDictionary_PutInteger(data->dictionary, SchemaInteger, 42); + + CCNxCodecNetworkBufferIoVec *vec = createIoVec(); + ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaIoVec, vec); + ccnxCodecNetworkBufferIoVec_Release(&vec); + + PARCJSON *json = parcJSON_ParseString("{\"KEY\": \"VALUE\"}"); + ccnxTlvDictionary_PutJson(data->dictionary, SchemaJson, json); + parcJSON_Release(&json); + + CCNxName *name = ccnxName_CreateFromCString("lci:/great/gatsby"); + ccnxTlvDictionary_PutName(data->dictionary, SchemaName, name); + ccnxName_Release(&name); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + parcMemory_Deallocate((void **) &data); +} + +// ============================================================= + +LONGBOW_TEST_RUNNER(rta_TlvDictionary) +{ + // 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(KnownKeys); + LONGBOW_RUN_TEST_FIXTURE(UnknownKeys); + LONGBOW_RUN_TEST_FIXTURE(Local); + + // type specific tests + LONGBOW_RUN_TEST_FIXTURE(Buffer); + LONGBOW_RUN_TEST_FIXTURE(Integer); + LONGBOW_RUN_TEST_FIXTURE(IoVec); + LONGBOW_RUN_TEST_FIXTURE(Json); + LONGBOW_RUN_TEST_FIXTURE(Name); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(rta_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(rta_TlvDictionary) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Performance); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Acquire); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Release); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_ContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Interest); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Control); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_InterestReturn); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetGetMessageTypeImplementation); + + + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_ShallowCopy); +} + +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, ccnxTlvDictionary_Performance) +{ + int reps = 100000; + struct timeval t0, t1; + gettimeofday(&t0, NULL); + for (int i = 0; i < reps; i++) { + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 20); + ccnxTlvDictionary_Release(&dictionary); + } + gettimeofday(&t1, NULL); + timersub(&t1, &t0, &t1); + double seconds = t1.tv_sec + t1.tv_usec * 1E-6; + + printf("time %.6f seconds, tps = %.2f\n", seconds, (double) reps / seconds); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Acquire) +{ + CCNxTlvDictionary *first = ccnxTlvDictionary_Create(10, 20); + CCNxTlvDictionary *second = ccnxTlvDictionary_Acquire(first); + + assertTrue(parcObject_GetReferenceCount(first) == 2, "Wrong ref count, got %" PRIu64 " expected %u", parcObject_GetReferenceCount(first), 2); + + ccnxTlvDictionary_Release(&second); + ccnxTlvDictionary_Release(&first); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Create) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 30); + assertNotNull(dictionary, "Got null dictionary from Create"); + assertNotNull(dictionary->directArray, "DirectArray is null"); + assertNotNull(dictionary->fixedListHeads, "fixedListHeads is null"); + + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Release) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_Release(&dictionary); + assertNull(dictionary, "Release did not null argument"); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_ContentObject) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + assertTrue(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Interest) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Control) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_Control(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_InterestReturn) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type"); + assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetGetMessageTypeImplementation) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1); + void *impl = ccnxTlvDictionary_GetMessageInterface(dictionary); + + assertNull(impl, "Expected a NULL implementation by default"); + + ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxContentObjectFacadeV1_Implementation); + assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxContentObjectFacadeV1_Implementation, + "Expected CCNxContentObjectFacadeV1_Implementation"); + + ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxContentObjectFacadeV1_Implementation); + assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxContentObjectFacadeV1_Implementation, + "Expected CCNxContentObjectFacadeV1_Implementation"); + + ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxInterestFacadeV1_Implementation); + assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxInterestFacadeV1_Implementation, + "Expected CCNxInterestFacadeV1_Implementation"); + + ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxInterestFacadeV1_Implementation); + assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxInterestFacadeV1_Implementation, + "Expected CCNxInterestFacadeV1_Implementation"); + + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Equals) +{ + CCNxTlvDictionary *a = ccnxTlvDictionary_Create(1, 1); + CCNxTlvDictionary *b = ccnxTlvDictionary_Create(1, 1); + CCNxTlvDictionary *c = ccnxTlvDictionary_Create(1, 1); + + ccnxTlvDictionary_SetMessageType_Interest(a, CCNxTlvDictionary_SchemaVersion_V1); + ccnxTlvDictionary_SetMessageType_Interest(b, CCNxTlvDictionary_SchemaVersion_V1); + ccnxTlvDictionary_SetMessageType_Interest(c, CCNxTlvDictionary_SchemaVersion_V1); + + CCNxTlvDictionary *diffArraySize = ccnxTlvDictionary_Create(2, 1); + CCNxTlvDictionary *diffListSize = ccnxTlvDictionary_Create(1, 2); + CCNxTlvDictionary *diffType = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_Control(diffType, CCNxTlvDictionary_SchemaVersion_V1); + + CCNxTlvDictionary *diffType2 = ccnxTlvDictionary_Create(1, 1); + ccnxTlvDictionary_SetMessageType_ContentObject(diffType2, CCNxTlvDictionary_SchemaVersion_V1); + + assertEqualsContract(ccnxTlvDictionary_Equals, a, b, c, diffArraySize, diffListSize, diffType, diffType2, NULL); + + ccnxTlvDictionary_Release(&diffType2); + ccnxTlvDictionary_Release(&diffType); + ccnxTlvDictionary_Release(&diffListSize); + ccnxTlvDictionary_Release(&diffArraySize); + ccnxTlvDictionary_Release(&c); + ccnxTlvDictionary_Release(&b); + ccnxTlvDictionary_Release(&a); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_ShallowCopy) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxTlvDictionary *a = data->dictionary; + + PARCBuffer *buffer = parcBuffer_WrapCString("Some Stuff"); + ccnxTlvDictionary_PutListBuffer(a, SchemaEnd, 23, buffer); + parcBuffer_Release(&buffer); + + CCNxTlvDictionary *b = ccnxTlvDictionary_ShallowCopy(a); + + assertTrue(ccnxTlvDictionary_Equals(a, b), "Expected Dictionaries to be Equal after ShallowCopy"); + + ccnxTlvDictionary_Release(&b); +} + +// ================================================================ + +LONGBOW_TEST_FIXTURE(KnownKeys) +{ + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_Exists); + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_NotExists); + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Unique); + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Duplicate); + + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Unique); + LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Duplicate); +} + +LONGBOW_TEST_FIXTURE_SETUP(KnownKeys) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(KnownKeys) +{ + _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(KnownKeys, ccnxTlvDictionary_Get_Exists) +{ + uint32_t key = SchemaEnd; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + + ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, key); + assertTrue(test == buffer, "Get value wrong, got %p expected %p", (void *) test, (void *) buffer); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_NotExists) +{ + uint32_t key = SchemaEnd; + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, key + 1); + assertNull(test, "Get for missing key should return null"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Unique) +{ + uint32_t key = SchemaEnd; + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer); + assertTrue(success, "Put returned false adding a unique key"); + parcBuffer_Release(&buffer); + + // one extra test particular to it being in the fast array + assertTrue(data->dictionary->directArray[key].entryType == ENTRY_BUFFER, "Not buffer type, got %d", data->dictionary->directArray[key].entryType); + assertNotNull(data->dictionary->directArray[key]._entry.buffer, "They fast array entry for key is null"); +} + +LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Duplicate) +{ + uint32_t key = SchemaEnd; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer); + bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer); + assertFalse(success, "Put returned true adding a duplicate key"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Unique) +{ + uint32_t listKey = SchemaEnd; + uint32_t bufferKey = 1000; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + assertTrue(success, "Put returned false adding a unique key"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Duplicate) +{ + uint32_t listKey = SchemaEnd; + uint32_t bufferKey = 1000; + + // its ok to have duplicates of the custom keys + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + assertTrue(success, "Put returned false adding a duplicate key to list"); + parcBuffer_Release(&buffer); +} + +// ================================================================ + +LONGBOW_TEST_FIXTURE(UnknownKeys) +{ + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Unique); + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Duplicate); + + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByPosition); + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByType); + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListSize); + LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListEquals); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownKeys) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownKeys) +{ + _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(UnknownKeys, ccnxTlvDictionary_PutList_Unique) +{ + uint32_t listKey = FIXED_LIST_LENGTH + 1; + uint32_t bufferKey = 1000; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + assertTrue(success, "Put returned false adding a unique key"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Duplicate) +{ + uint32_t listKey = FIXED_LIST_LENGTH + 1; + uint32_t bufferKey = 1000; + + // its ok to have duplicates of the custom keys + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer); + assertTrue(success, "Put returned false adding a duplicate key to list"); + parcBuffer_Release(&buffer); +} + +/* + * Add 3 items to list then make sure we can retrieve the 2nd + */ +LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByPosition) +{ + uint32_t listKey = SchemaEnd; + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *a = parcBuffer_Allocate(1); + PARCBuffer *b = parcBuffer_Allocate(1); + PARCBuffer *c = parcBuffer_Allocate(1); + + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c); + + PARCBuffer *test = NULL; + uint32_t testkey = 0; + ccnxTlvDictionary_ListGetByPosition(data->dictionary, listKey, 1, &test, &testkey); + + assertTrue(testkey == 1001, "Wrong key, expected %u got %u", 1001, testkey); + assertTrue(test == b, "Wrong buffer, expected %p got %p", (void *) b, (void *) test); + + parcBuffer_Release(&a); + parcBuffer_Release(&b); + parcBuffer_Release(&c); +} + +/* + * Add 3 items to list then make sure we can retrieve the 2nd + */ +LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByType) +{ + uint32_t listKey = SchemaEnd; + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *a = parcBuffer_Allocate(1); + PARCBuffer *b = parcBuffer_Allocate(1); + PARCBuffer *c = parcBuffer_Allocate(1); + + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c); + + PARCBuffer *test = ccnxTlvDictionary_ListGetByType(data->dictionary, listKey, 1001); + assertTrue(test == b, "Wrong buffer, expected %p got %p", (void *) b, (void *) test); + + parcBuffer_Release(&a); + parcBuffer_Release(&b); + parcBuffer_Release(&c); +} + +LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListSize) +{ + uint32_t listKey = SchemaEnd; + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *a = parcBuffer_Allocate(1); + PARCBuffer *b = parcBuffer_Allocate(1); + PARCBuffer *c = parcBuffer_Allocate(1); + + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b); + ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c); + + size_t length = ccnxTlvDictionary_ListSize(data->dictionary, listKey); + assertTrue(length == 3, "Wrong length, expected %u got %zu", 3, length); + + parcBuffer_Release(&a); + parcBuffer_Release(&b); + parcBuffer_Release(&c); +} + +LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListEquals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *a = parcBuffer_Allocate(1); + PARCBuffer *b = parcBuffer_Allocate(1); + PARCBuffer *c = parcBuffer_Allocate(1); + + ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1000, a); + ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1001, b); + ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1002, c); + + ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1000, a); + ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1001, b); + ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1002, c); + + bool equals = _ccnxTlvDictionary_ListEquals(_getListHead(data->dictionary, 6), _getListHead(data->dictionary, 7)); + assertTrue(equals, "Lists should be equal"); + + parcBuffer_Release(&a); + parcBuffer_Release(&b); + parcBuffer_Release(&c); +} + + + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Buffer) +{ + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Exists); + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Missing); + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_OK); + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_Duplicate); + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_True); + LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Buffer) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Buffer) +{ + _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(Buffer, ccnxTlvDictionary_GetBuffer_Exists) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, SchemaBuffer); + assertNotNull(test, "Got null buffer from key that hsould be buffer"); +} + +LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxTlvDictionary_GetBuffer(data->dictionary, SchemaFree); +} + +LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaFree, buffer); + assertTrue(success, "Did not put buffer in to available slot"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_Duplicate) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = parcBuffer_Allocate(1); + bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaBuffer, buffer); + assertFalse(success, "Should have failed putting duplicate"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_True) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueBuffer(data->dictionary, SchemaBuffer); + assertTrue(success, "Should have succeeded on a buffer key"); +} + +LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_False) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueBuffer(data->dictionary, SchemaInteger); + assertFalse(success, "Should have failed on a non-buffer"); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Integer) +{ + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_GetInteger_Exists); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_GetInteger_Missing); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OK); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_Duplicate); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OverBuffer); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_True); + LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Integer) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Integer) +{ + _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(Integer, ccnxTlvDictionary_GetInteger_Exists) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint64_t test = ccnxTlvDictionary_GetInteger(data->dictionary, SchemaInteger); + assertTrue(test == 42, "Got wrong integer, got %" PRIu64 " expected 42", test); +} + +LONGBOW_TEST_CASE_EXPECTS(Integer, ccnxTlvDictionary_GetInteger_Missing, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxTlvDictionary_GetInteger(data->dictionary, SchemaBuffer); +} + +LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaFree, 69); + assertTrue(success, "Did not put integer in to available slot"); +} + +LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_Duplicate) +{ + // we allow replacing integer + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaInteger, 69); + assertTrue(success, "Should have succeeded putting duplicate"); +} + +LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OverBuffer) +{ + // This will fail, cannot change a buffer to an integer + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaBuffer, 69); + assertFalse(success, "Should not be able to change a buffer to an integer"); +} + +LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_True) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueInteger(data->dictionary, SchemaInteger); + assertTrue(success, "Should have succeeded on a integer key"); +} + +LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_False) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueInteger(data->dictionary, SchemaBuffer); + assertFalse(success, "Should have failed on a non-integer"); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(IoVec) +{ + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Exists); + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Missing); + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_OK); + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_Duplicate); + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_True); + LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(IoVec) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(IoVec) +{ + _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(IoVec, ccnxTlvDictionary_GetIoVec_Exists) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxCodecNetworkBufferIoVec *test = ccnxTlvDictionary_GetIoVec(data->dictionary, SchemaIoVec); + assertNotNull(test, "Got null buffer from key that hsould be buffer"); +} + +LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxTlvDictionary_GetIoVec(data->dictionary, SchemaFree); +} + +LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxCodecNetworkBufferIoVec *vec = createIoVec(); + bool success = ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaFree, vec); + assertTrue(success, "Did not put vec in to available slot"); + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_Duplicate) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxCodecNetworkBufferIoVec *vec = createIoVec(); + bool success = ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaIoVec, vec); + assertFalse(success, "Should have failed putting duplicate"); + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_True) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueIoVec(data->dictionary, SchemaIoVec); + assertTrue(success, "Should have succeeded on a vec key"); +} + +LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_False) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueIoVec(data->dictionary, SchemaInteger); + assertFalse(success, "Should have failed on a non-vec"); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Json) +{ + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Exists); + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Missing); + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_PutJson_OK); + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_PutJson_Duplicate); + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_True); + LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Json) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Json) +{ + _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(Json, ccnxTlvDictionary_GetJson_Exists) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCJSON *test = ccnxTlvDictionary_GetJson(data->dictionary, SchemaJson); + assertNotNull(test, "Got null json from key that should be json"); +} + +LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCJSON *test = ccnxTlvDictionary_GetJson(data->dictionary, SchemaFree); + assertNull(test, "Should have gotten null for non-json key"); +} + +LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_PutJson_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCJSON *json = parcJSON_Create(); + bool success = ccnxTlvDictionary_PutJson(data->dictionary, SchemaFree, json); + assertTrue(success, "Did not put buffer in to available slot"); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_PutJson_Duplicate) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCJSON *json = parcJSON_Create(); + bool success = ccnxTlvDictionary_PutJson(data->dictionary, SchemaJson, json); + assertFalse(success, "Should have failed putting duplicate"); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_True) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueJson(data->dictionary, SchemaJson); + assertTrue(success, "Should have succeeded on a json key"); +} + +LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_False) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueJson(data->dictionary, SchemaInteger); + assertFalse(success, "Should have failed on a non-json"); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Name) +{ + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_GetName_Exists); + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_GetName_Missing); + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_PutName_OK); + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_PutName_Duplicate); + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_True); + LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Name) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Name) +{ + _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(Name, ccnxTlvDictionary_GetName_Exists) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = ccnxTlvDictionary_GetName(data->dictionary, SchemaName); + assertNotNull(test, "Got null json from key that should be name"); +} + +LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_GetName_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = ccnxTlvDictionary_GetName(data->dictionary, SchemaFree); + assertNull(test, "Should have gotten null for non-name key"); +} + +LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_PutName_OK) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *name = ccnxName_Create(); + bool success = ccnxTlvDictionary_PutName(data->dictionary, SchemaFree, name); + assertTrue(success, "Did not put name in to available slot"); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_PutName_Duplicate) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *name = ccnxName_Create(); + bool success = ccnxTlvDictionary_PutName(data->dictionary, SchemaName, name); + assertFalse(success, "Should have failed putting duplicate"); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_True) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueName(data->dictionary, SchemaName); + assertTrue(success, "Should have succeeded on a json key"); +} + +LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_False) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success = ccnxTlvDictionary_IsValueName(data->dictionary, SchemaInteger); + assertFalse(success, "Should have failed on a non-json"); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Unset); + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Buffer); + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Integer); + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_IoVec); + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Json); + LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Name); +} + +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; +} + +static void +assertRtaTlvEntryEquals(int length, _CCNxTlvDictionaryEntry array[length]) +{ + assertTrue(length == 5, "Must provide 5 array elements"); + assertEqualsContract((bool (*)(void *, void *))_ccnxTlvDictionaryEntry_Equals, &array[0], &array[1], &array[2], &array[3], &array[4], NULL); +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Unset) +{ + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_BUFFER; + assertRtaTlvEntryEquals(5, array); +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Buffer) +{ + char apple[] = "apple"; + char bananna[] = "bannana"; + + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + for (int i = 0; i < 3; i++) { + array[i].entryType = ENTRY_BUFFER; + array[i]._entry.buffer = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), sizeof(apple), (uint8_t *) apple)); + } + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_BUFFER; + array[4]._entry.buffer = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), sizeof(bananna), (uint8_t *) bananna)); + assertRtaTlvEntryEquals(5, array); + + for (int i = 0; i < 5; i++) { + if (array[i]._entry.buffer) { + parcBuffer_Release(&array[i]._entry.buffer); + } + } +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Integer) +{ + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + for (int i = 0; i < 3; i++) { + array[i].entryType = ENTRY_INTEGER; + array[i]._entry.integer = 13; + } + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_INTEGER; + array[4]._entry.integer = 99; + + assertRtaTlvEntryEquals(5, array); +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_IoVec) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL); + ccnxCodecNetworkBuffer_PutUint8(netbuff, 0); + CCNxCodecNetworkBufferIoVec *unequal = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + ccnxCodecNetworkBuffer_Release(&netbuff); + + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + for (int i = 0; i < 3; i++) { + array[i].entryType = ENTRY_IOVEC; + array[i]._entry.vec = createIoVec(); + } + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_IOVEC; + array[4]._entry.vec = unequal; + assertRtaTlvEntryEquals(5, array); + + for (int i = 0; i < 5; i++) { + if (array[i]._entry.vec) { + ccnxCodecNetworkBufferIoVec_Release(&array[i]._entry.vec); + } + } +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Json) +{ + char apple[] = "{\"apple\": 0}"; + char bananna[] = "{\"bannana\": 1}"; + + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + for (int i = 0; i < 3; i++) { + array[i].entryType = ENTRY_JSON; + array[i]._entry.json = parcJSON_ParseString(apple); + } + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_JSON; + array[4]._entry.json = parcJSON_ParseString(bananna); + assertRtaTlvEntryEquals(5, array); + + for (int i = 0; i < 5; i++) { + if (array[i]._entry.json) { + parcJSON_Release(&array[i]._entry.json); + } + } +} + +LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Name) +{ + char apple[] = "lci:/apple"; + char bananna[] = "lci:/bannana"; + + _CCNxTlvDictionaryEntry array[5]; + memset(&array, 0, sizeof(array)); + + for (int i = 0; i < 3; i++) { + array[i].entryType = ENTRY_NAME; + array[i]._entry.name = ccnxName_CreateFromCString(apple); + } + + array[3].entryType = ENTRY_JSON; + array[4].entryType = ENTRY_NAME; + array[4]._entry.name = ccnxName_CreateFromCString(bananna); + assertRtaTlvEntryEquals(5, array); + + for (int i = 0; i < 5; i++) { + if (array[i]._entry.name) { + ccnxName_Release(&array[i]._entry.name); + } + } +} + +// ============================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvDictionary); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade Binary files differnew file mode 100755 index 00000000..39a27830 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c new file mode 100755 index 00000000..fe3ead29 --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c @@ -0,0 +1,444 @@ +/* + * 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. + */ + +/** + * Setter tests use ground truth by examining the dictionary. + * Getter tests use the setters to set values. + * + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_ValidationFacadeV1.c" + +#include <stdio.h> +#include <inttypes.h> + +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +//#include "../validation/test/testrig_validation.c" + +LONGBOW_TEST_RUNNER(ccnx_ValidationFacadeV1) +{ + // 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(Setters); + LONGBOW_RUN_TEST_FIXTURE(Getters); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ValidationFacadeV1) +{ + 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_ValidationFacadeV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Setters) +{ + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyId); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyName); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPublicKey); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCertificate); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPayload); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCryptoSuite); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetSigningTime); +} + +LONGBOW_TEST_FIXTURE_SETUP(Setters) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Setters) +{ + 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(Setters, ccnxValidationFacadeV1_SetKeyId) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + bool success = ccnxValidationFacadeV1_SetKeyId(dictionary, keyid); + assertTrue(success, "Failed to set keyid"); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + assertTrue(parcBuffer_Equals(test, keyid), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&keyid); + ccnxTlvDictionary_Release(&dictionary); +} + + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyName) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + PARCBuffer *hash = parcBuffer_Wrap((uint8_t []) { 11, 12, 13, 14 }, 4, 0, 4); + CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + CCNxLink *link = ccnxLink_Create(name, keyid, hash); + + bool success = ccnxValidationFacadeV1_SetKeyName(dictionary, link); + assertTrue(success, "Failed to set keyname"); + + CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME); + assertTrue(ccnxName_Equals(testName, name), "Wrong name") + { + 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), "Wrong keyid") + { + 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), "Wrong hash") + { + printf("Expected\n"); + parcBuffer_Display(hash, 3); + printf("Got\n"); + parcBuffer_Display(testHash, 3); + } + + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + ccnxLink_Release(&link); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPublicKey) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *key = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + bool success = ccnxValidationFacadeV1_SetPublicKey(dictionary, key); + assertTrue(success, "Failed to set keyid"); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); + assertTrue(parcBuffer_Equals(test, key), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(key, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&key); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCertificate) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *cert = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + bool success = ccnxValidationFacadeV1_SetCertificate(dictionary, cert); + assertTrue(success, "Failed to set keyid"); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); + assertTrue(parcBuffer_Equals(test, cert), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(cert, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&cert); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPayload) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *payload = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + bool success = ccnxValidationFacadeV1_SetPayload(dictionary, payload); + assertTrue(success, "Failed to set keyid"); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + assertTrue(parcBuffer_Equals(test, payload), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(payload, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&payload); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCryptoSuite) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256; + bool success = ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite); + assertTrue(success, "Failed to set keyid"); + + bool hasCryptoSuite = ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(hasCryptoSuite, "Dictionary does not have a crypto suite value in it"); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == suite, "Wrong suite, expected %d got %d", suite, test); + + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetSigningTime) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + uint64_t signingTime = 0x0102030405060708ULL; + + bool success = ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime); + assertTrue(success, "Failed to set signing time"); + + bool hasSigningTime = ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + assertTrue(hasSigningTime, "Dictionary does not have a signing time value in it"); + + uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + assertTrue(test == signingTime, "Wrong signing time, expected %" PRIx64 " got %" PRIx64, signingTime, test); + + ccnxTlvDictionary_Release(&dictionary); +} + +// ============================================================= + +LONGBOW_TEST_FIXTURE(Getters) +{ + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyId); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyName); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPublicKey); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCertificate); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPayload); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_True); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_False); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCryptoSuite); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_True); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_False); + LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetSigningTime); +} + +LONGBOW_TEST_FIXTURE_SETUP(Getters) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Getters) +{ + 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(Setters, ccnxValidationFacadeV1_GetKeyId) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + ccnxValidationFacadeV1_SetKeyId(dictionary, keyid); + + PARCBuffer *test = ccnxValidationFacadeV1_GetKeyId(dictionary); + assertTrue(parcBuffer_Equals(test, keyid), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&keyid); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyName) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + PARCBuffer *hash = parcBuffer_Wrap((uint8_t []) { 11, 12, 13, 14 }, 4, 0, 4); + CCNxName *name = ccnxName_CreateFromCString("lci:/foo"); + CCNxLink *link = ccnxLink_Create(name, keyid, hash); + + ccnxValidationFacadeV1_SetKeyName(dictionary, link); + + CCNxLink *testLink = ccnxValidationFacadeV1_GetKeyName(dictionary); + assertTrue(ccnxLink_Equals(testLink, link), "Wrong link"); + // no ccnxLink_Dispay, so cannot easily display items + + ccnxLink_Release(&testLink); + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + ccnxLink_Release(&link); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPublicKey) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *key = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + ccnxValidationFacadeV1_SetPublicKey(dictionary, key); + + PARCBuffer *test = ccnxValidationFacadeV1_GetPublicKey(dictionary); + assertTrue(parcBuffer_Equals(test, key), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(key, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&key); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCertificate) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *cert = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + ccnxValidationFacadeV1_SetCertificate(dictionary, cert); + + PARCBuffer *test = ccnxValidationFacadeV1_GetCertificate(dictionary); + assertTrue(parcBuffer_Equals(test, cert), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(cert, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&cert); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPayload) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCBuffer *payload = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5); + ccnxValidationFacadeV1_SetPayload(dictionary, payload); + + PARCBuffer *test = ccnxValidationFacadeV1_GetPayload(dictionary); + assertTrue(parcBuffer_Equals(test, payload), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(payload, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&payload); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_True) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256; + ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite); + + bool hasCryptoSuite = ccnxValidationFacadeV1_HasCryptoSuite(dictionary); + assertTrue(hasCryptoSuite, "Dictionary does not have a crypto suite value in it"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_False) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + bool hasCryptoSuite = ccnxValidationFacadeV1_HasCryptoSuite(dictionary); + assertFalse(hasCryptoSuite, "Dictionary says it has a crypto suite when none was set"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCryptoSuite) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256; + ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite); + + PARCCryptoSuite test = ccnxValidationFacadeV1_GetCryptoSuite(dictionary); + assertTrue(test == suite, "Wrong crypto suite, expected %d got %d", suite, test); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_True) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + uint64_t signingTime = 0x0102030405060708ULL; + ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime); + + bool hasSigningTime = ccnxValidationFacadeV1_HasSigningTime(dictionary); + assertTrue(hasSigningTime, "Dictionary does not have a signing time value in it"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_False) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + bool hasSigningTime = ccnxValidationFacadeV1_HasSigningTime(dictionary); + assertFalse(hasSigningTime, "Dictionary says it has a signing time when none was set"); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetSigningTime) +{ + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + uint64_t signingTime = 0x0102030405060708ULL; + ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime); + + uint64_t test = ccnxValidationFacadeV1_GetSigningTime(dictionary); + assertTrue(test == signingTime, "Wrong signing time, expected %" PRIx64 " got %" PRIx64, signingTime, test); + ccnxTlvDictionary_Release(&dictionary); +} + + +// ============================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ValidationFacadeV1); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c new file mode 100755 index 00000000..194ef02c --- /dev/null +++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c @@ -0,0 +1,594 @@ +/* + * 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 "../ccnx_WireFormatFacadeV1.c" + +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +#include <ccnx/common/ccnx_ContentObject.h> +#include <ccnx/common/ccnx_WireFormatMessage.h> +#include <ccnx/common/codec/ccnxCodec_TlvPacket.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 <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h> + +LONGBOW_TEST_RUNNER(ccnx_WireFormatFacade) +{ + // 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(SchemaV1); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_WireFormatFacade) +{ + 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_WireFormatFacade) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Small size allocator for creating a network buffer + */ +static size_t +allocator(void *userarg, size_t bytes, void **output) +{ + const size_t allocationSize = *(size_t *) userarg; + void *allocated = parcMemory_Allocate(allocationSize); + *output = allocated; + return allocationSize; +} + +/* + * deallocator for network buffer + */ +static void +deallocator(void *userarg, void **memoryPtr) +{ + parcMemory_Deallocate(memoryPtr); +} + +static const CCNxCodecNetworkBufferMemoryBlockFunctions memory = { .allocator = allocator, .deallocator = deallocator }; + +/* + * Create a network buffer that looks like this. The actual number of iovecs might + * be a little different, but the digest area will span several iovec. + * + * +-----------+-----------+-----------+-----------+-----------+ + * iov[0] iov[1] iov[2] iov[3] + * +-----------+-----------+-----------+-----------+-----------+ + * ^ ^ + * | | + * start end + */ +static CCNxCodecNetworkBufferIoVec * +createNetworkBufferIoVec(size_t allocationSize, size_t padlen, uint8_t pad[padlen], size_t datalen, uint8_t data[datalen]) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&memory, &allocationSize); + // build the network buffer + ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad); + ccnxCodecNetworkBuffer_PutArray(netbuff, datalen, data); + ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad); + + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + ccnxCodecNetworkBuffer_Release(&netbuff); + return vec; +} + +// ======================================================================= + +LONGBOW_TEST_FIXTURE(SchemaV1) +{ + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromContentObjectPacketType); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromControlPacketType); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketType); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestReturnPacketType); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Get); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Put); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_WriteToFile); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_GetIoVec); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetHopLimit); + + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionStart); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionLength); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_Buffer); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_IoVec); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_ComputeContentObjectHash); + + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Interest); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_ContentObject); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Control); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_InterestReturn); + LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_UnknownPacketType); +} + +LONGBOW_TEST_FIXTURE_SETUP(SchemaV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(SchemaV1) +{ + 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(SchemaV1, ccnxWireFormatFacadeV1_FromContentObjectPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer); + assertNotNull(wireformat, "Got null wireformat"); + assertTrue(ccnxTlvDictionary_IsContentObject(wireformat), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromControlPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromControlPacketType(buffer); + assertNotNull(wireformat, "Got null wireformat"); + assertTrue(ccnxTlvDictionary_IsControl(wireformat), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer); + assertNotNull(wireformat, "Got null wireformat"); + assertTrue(ccnxTlvDictionary_IsInterest(wireformat), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestReturnPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestReturnPacketType(buffer); + assertNotNull(wireformat, "Got null wireformat"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(wireformat), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Get) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer); + + PARCBuffer *test = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(wireformat); + assertTrue(test == buffer, "Wrong iovec: got %p expected %p", (void *) test, (void *) buffer); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Put) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *packet = ccnxTlvDictionary_Create(20, 20); + ccnxTlvDictionary_SetMessageType_Interest(packet, CCNxTlvDictionary_SchemaVersion_V1); + bool success = _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer); + + assertTrue(success, "Failed to put buffer in to dictionary"); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_WriteToFile) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer); + + _ccnxWireFormatFacadeV1_WriteToFile(wireformat, "/dev/null"); + + ccnxTlvDictionary_Release(&wireformat); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec) +{ + uint8_t data[64]; + + uint8_t pad[32]; + CCNxCodecNetworkBufferIoVec *vec = createNetworkBufferIoVec(512, 32, pad, 64, data); + + CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec(vec); + assertNotNull(wireformat, "Got null wireformat"); + assertTrue(ccnxTlvDictionary_IsInterest(wireformat), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxTlvDictionary_Release(&wireformat); + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_GetIoVec) +{ + uint8_t *data = parcMemory_Allocate(64); + memset(data, 0, 64); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec); + + CCNxCodecNetworkBufferIoVec *test = _ccnxWireFormatFacadeV1_GetIoVec(packet); + assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetHopLimit) +{ + uint8_t *data = parcMemory_Allocate(64); + memset(data, 0, 64); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec); + + _ccnxWireFormatFacadeV1_SetHopLimit(packet, 10); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxCodecNetworkBuffer_Release(&netbuff); + + CCNxCodecSchemaV1InterestHeader header; + + buffer = parcBuffer_Wrap((void *) &header, sizeof(header), 0, sizeof(header)); + + packet = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer); + + _ccnxWireFormatFacadeV1_SetHopLimit(packet, 10); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionStart) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer); + + size_t start = 5; + bool success = _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, start); + assertTrue(success, "Failed to put integer in to dictionary"); + + assertTrue(ccnxTlvDictionary_IsValueInteger(packet, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart), "ProtectedStart not set"); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionLength) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer); + + size_t length = 5; + bool success = _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, length); + assertTrue(success, "Failed to put integer in to dictionary"); + + assertTrue(ccnxTlvDictionary_IsValueInteger(packet, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength), "ProtectedLength not set"); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_Buffer) +{ + // >1234< + const char string[] = "Hello dev null\n"; + + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + size_t start = 5; + size_t length = 4; + + CCNxTlvDictionary *packet = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer); + _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, start); + _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, length); + + PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + PARCCryptoHash *hash = _ccnxWireFormatFacadeV1_HashProtectedRegion(packet, hasher); + + // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash + assertNotNull(hash, "Got null hash from a good packet"); + + ccnxTlvDictionary_Release(&packet); + parcCryptoHash_Release(&hash); + parcBuffer_Release(&buffer); + parcCryptoHasher_Release(&hasher); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_IoVec) +{ + uint8_t *data = parcMemory_Allocate(64); + memset(data, 0, 64); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec); + + _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, 0); + _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, 64); + + PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + PARCCryptoHash *hash = _ccnxWireFormatFacadeV1_HashProtectedRegion(packet, hasher); + + // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash + assertNotNull(hash, "Got null hash from a good packet"); + + ccnxTlvDictionary_Release(&packet); + parcCryptoHash_Release(&hash); + parcBuffer_Release(&buffer); + parcCryptoHasher_Release(&hasher); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Interest) +{ + PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA)); + CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat); + assertNotNull(test, "Got null dictionary for good interest"); + assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary says it is not an Interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1"); + parcBuffer_Release(&wireFormat); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_ContentObject) +{ + PARCBuffer *wireFormat = parcBuffer_Wrap(v1_content_nameA_crc32c, sizeof(v1_content_nameA_crc32c), 0, sizeof(v1_content_nameA_crc32c)); + CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat); + assertNotNull(test, "Got null dictionary for good content object"); + assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary says it is not a Content Object"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1"); + parcBuffer_Release(&wireFormat); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Control) +{ + PARCBuffer *wireFormat = parcBuffer_Wrap(v1_cpi_add_route, sizeof(v1_cpi_add_route), 0, sizeof(v1_cpi_add_route)); + CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat); + assertNotNull(test, "Got null dictionary for good control"); + assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary says it is not a control"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1"); + parcBuffer_Release(&wireFormat); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_InterestReturn) +{ + uint8_t encoded[] = { 1, CCNxCodecSchemaV1Types_PacketType_InterestReturn, 0, 23 }; + PARCBuffer *wireFormat = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat); + assertNotNull(test, "Got null dictionary for good InterestReturn"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Expected IsInterestReturn() to be true"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1"); + parcBuffer_Release(&wireFormat); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_UnknownPacketType) +{ + uint8_t encoded[] = { 1, 99, 0, 23 }; + PARCBuffer *wireFormat = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat); + assertNull(test, "Should have gotten null dictionary for unknown packet type"); + parcBuffer_Release(&wireFormat); +} + + +static uint8_t _v1_ContentObject_WithKnownHash[] = { + // Name: lci:/boose/roo/pie + // Payload: "this is the payload" + // Signer: CRC32 + // CO Hash: 4FB301EA5FD523B9A71287B721DC20C94B2D4827674A8CA275B7D57C60447876 + + 0x01, 0x01, 0x00, 0x4e, // Fixed Header + 0x00, 0x00, 0x00, 0x08, + + 0x00, 0x02, 0x00, 0x32, // Type 2 == ContentObject, length 50 (0x32) + 0x00, 0x00, 0x00, 0x17, // Name, length 23 (0x17) + + 0x00, 0x01, 0x00, 0x05, // NameSegment, length 5 + 0x62, 0x6f, 0x6f, 0x73, // "boose" + 0x65, + + 0x00, 0x01, 0x00, 0x03, // NameSegment, length 3 + 0x72, 0x6f, 0x6f, // "roo" + + 0x00, 0x01, 0x00, 0x03, // NameSegment, length 3 + 0x70, 0x69, 0x65, // "pie" + + 0x00, 0x01, 0x00, 0x13, // Payload, length 19 (0x13) + 0x74, 0x68, 0x69, 0x73, // "this is the payload" + 0x20, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, + 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, + + 0x00, 0x03, 0x00, 0x04, // Validation Alg, length 4 + 0x00, 0x02, 0x00, 0x00, // CRC32, length 0 + + 0x00, 0x04, 0x00, 0x04, // Validation Payload, length 4 + 0x7e, 0x60, 0x54, 0xc4, // The payload (the CRC32) +}; + +LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_ComputeContentObjectHash) +{ + PARCBuffer *wireFormatBuffer = parcBuffer_Wrap(_v1_ContentObject_WithKnownHash, sizeof(_v1_ContentObject_WithKnownHash), + 0, sizeof(_v1_ContentObject_WithKnownHash)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormatBuffer); + + CCNxTlvDictionary *contentObject = ccnxWireFormatMessage_GetDictionary(message); + + // We have a partially unpacked dictionary now, but we need to more fully unpack it for our processing. + assertTrue(ccnxCodecTlvPacket_BufferDecode(wireFormatBuffer, contentObject), "Expected to decode the wireformat buffer"); + + + PARCCryptoHash *coHash = _ccnxWireFormatFacadeV1_ComputeContentObjectHash(contentObject); + + assertNotNull(coHash, "Expected a non-NULL content object hash"); + + char *computedHash = parcBuffer_ToHexString(parcCryptoHash_GetDigest(coHash)); + + char *knownHash = "4FB301EA5FD523B9A71287B721DC20C94B2D4827674A8CA275B7D57C60447876"; + + assertTrue(strncasecmp(computedHash, knownHash, strlen(knownHash)) == 0, "Expected a matching ContentObject hash"); + + parcMemory_Deallocate(&computedHash); + parcCryptoHash_Release(&coHash); + parcBuffer_Release(&wireFormatBuffer); + + ccnxContentObject_Release(&contentObject); +} + +// ======================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _ccnxWireFormatFacadeV1_ComputeHash); +} + +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, _ccnxWireFormatFacadeV1_ComputeHash) +{ + // >1234< + const char string[] = "Hello dev null\n"; + const char substring[] = " dev"; + + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + size_t start = 5; + size_t length = 4; + + + // compute the true hash + PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + parcCryptoHasher_Init(hasher); + parcCryptoHasher_UpdateBytes(hasher, substring, length); + PARCCryptoHash *truthHash = parcCryptoHasher_Finalize(hasher); + + // Compute the test hash + PARCCryptoHash *testHash = _ccnxWireFormatFacadeV1_ComputeBufferHash(buffer, hasher, start, length); + + // Test + bool equals = parcCryptoHash_Equals(truthHash, testHash); + assertTrue(equals, "Hashes do not match") + { + PARCBuffer *truthBuffer = parcCryptoHash_GetDigest(truthHash); + PARCBuffer *testBuffer = parcCryptoHash_GetDigest(testHash); + + printf("Expected:\n"); + parcBuffer_Display(truthBuffer, 3); + + printf("Got:\n"); + parcBuffer_Display(testBuffer, 3); + } + + parcCryptoHash_Release(&truthHash); + parcCryptoHash_Release(&testHash); + parcBuffer_Release(&buffer); + parcCryptoHasher_Release(&hasher); +} + +// ======================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_WireFormatFacade); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |