aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-portal/ccnx/api/ccnx_Portal
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-portal/ccnx/api/ccnx_Portal')
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt52
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h54
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c257
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h529
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c140
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h44
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c258
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h396
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c39
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h52
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c136
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h236
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c452
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h82
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c191
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h330
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore5
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt19
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c159
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c136
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c21
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c218
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h54
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h54
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/config.h.in3
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore6
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex9
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex46
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex501
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls280
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex46
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md16
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.grafflebin0 -> 9624 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdfbin0 -> 29817 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex15
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdfbin0 -> 26633 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.pngbin0 -> 24543 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib8
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore9
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt18
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/LOG25
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c826
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c175
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c286
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c245
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c217
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c366
50 files changed, 7143 insertions, 0 deletions
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt
new file mode 100644
index 00000000..b4d2a136
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Define a few configuration variables that we want accessible in the software
+
+configure_file(config.h.in config.h @ONLY)
+
+set(CCNX_API_PORTAL_HEADERS
+ ccnx_Portal.h
+ ccnx_PortalFactory.h
+ ccnx_PortalAttributes.h
+ ccnx_PortalStack.h
+ ccnx_PortalRTA.h
+ ccnx_PortalAPI.h
+ ccnx_PortalAnchor.h
+ ccnxPortal_About.h
+ )
+
+set(CCNX_API_PORTAL_SOURCE_FILES
+ ${CCNX_API_PORTAL_HEADERS}
+ ccnx_Portal.c
+ ccnx_PortalFactory.c
+ ccnx_PortalAttributes.c
+ ccnx_PortalStack.c
+ ccnx_PortalRTA.c
+ ccnx_PortalAPI.c
+ ccnx_PortalAnchor.c
+ ccnxPortal_About.c
+ )
+
+source_group(Sources FILES ${CCNX_API_PORTAL_SOURCE_FILES})
+source_group(Sources FILES ${CCNX_API_PORTAL_HEADERS})
+
+add_library(ccnx_api_portal STATIC ${CCNX_API_PORTAL_SOURCE_FILES} ${CCNX_API_PORTAL_HEADER_FILES})
+add_library(ccnx_api_portal.shared SHARED ${CCNX_API_PORTAL_SOURCE_FILES})
+set_target_properties(ccnx_api_portal.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_api_portal )
+
+set(libccnx_api_portal_libraries
+ ccnx_api_portal
+ ccnx_api_portal.shared
+ )
+
+foreach(lib ${libccnx_api_portal_libraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${CCNX_API_PORTAL_HEADERS} DESTINATION include/ccnx/api/ccnx_Portal )
+
+add_subdirectory(test)
+add_subdirectory(command-line)
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c
new file mode 100644
index 00000000..a942db2c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortal_About.h"
+
+const char *ccnxPortal_What = "@(#)" "CCNx Portal API " RELEASE_VERSION " 2017-02-22T13:18:15.247445"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalAbout_Name(void)
+{
+ return "CCNx Portal API";
+}
+
+const char *
+ccnxPortalAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalAbout_About(void)
+{
+ return "CCNx Portal API "RELEASE_VERSION " 2017-02-22T13:18:15.247445" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_LongNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n";
+}
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h
new file mode 100755
index 00000000..47c6651f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortal_About_h
+#define ccnxPortal_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortal_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_LongNotice(void);
+
+#endif // ccnxPortal_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c
new file mode 100755
index 00000000..94e36086
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c
@@ -0,0 +1,257 @@
+/*
+ * 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 <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+
+#include <ccnx/transport/common/transport.h>
+
+struct ccnx_portal_status {
+ int error;
+ bool eof;
+};
+
+struct ccnx_portal {
+ CCNxPortalStatus status;
+
+ const CCNxPortalStack *stack;
+};
+
+static CCNxMetaMessage *
+_ccnxPortal_ComposeAnchorMessage(const CCNxName *routerName, const CCNxName *name, int secondsToLive)
+{
+ time_t expireTime = time(0) + secondsToLive;
+ CCNxPortalAnchor *namePrefix = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_Serialize(namePrefix, composer);
+ PARCBuffer *payload = parcBufferComposer_ProduceBuffer(composer);
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(routerName);
+ ccnxInterest_SetPayload(interest, payload);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ parcBuffer_Release(&payload);
+ ccnxInterest_Release(&interest);
+ parcBufferComposer_Release(&composer);
+ ccnxPortalAnchor_Release(&namePrefix);
+
+ return message;
+}
+
+static int
+_ccnxPortal_SetAnchor(CCNxPortal *portal, const CCNxName *name, time_t secondsToLive)
+{
+ int64_t timeOutMicroSeconds = parcProperties_GetAsInteger(ccnxPortalStack_GetProperties(portal->stack), CCNxPortalFactory_LocalRouterTimeout, 1000000);
+
+ CCNxName *routerName = ccnxName_CreateFromCString(ccnxPortalStack_GetProperty(portal->stack, CCNxPortalFactory_LocalRouterName, "lci:/local/dcr"));
+ CCNxName *fullName = ccnxName_ComposeNAME(routerName, "anchor");
+
+ CCNxMetaMessage *message = _ccnxPortal_ComposeAnchorMessage(fullName, name, secondsToLive);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_MicroSeconds(timeOutMicroSeconds));
+ ccnxMetaMessage_Release(&message);
+
+ CCNxMetaMessage *response = ccnxPortal_Receive(portal, CCNxStackTimeout_MicroSeconds(timeOutMicroSeconds));
+ if (response != NULL) {
+ ccnxMetaMessage_Release(&response);
+ }
+
+ ccnxName_Release(&fullName);
+ ccnxName_Release(&routerName);
+
+ return 0;
+}
+
+bool
+ccnxPortal_Flush(CCNxPortal *portal, const CCNxStackTimeout *timeout)
+{
+ CCNxControl *control = ccnxControl_CreateFlushRequest();
+
+ // this needs to be better wrapped in ccnxControl
+ PARCJSON *json = ccnxControl_GetJson(control);
+ uint64_t expectedSequenceNumber = controlPlaneInterface_GetSequenceNumber(json);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+ bool result = ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxControl_Release(&control);
+
+ if (result == true) {
+ bool matchedSequenceNumber = false;
+ while (!matchedSequenceNumber) {
+ message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ if (message) {
+ if (ccnxMetaMessage_IsControl(message)) {
+ control = ccnxMetaMessage_GetControl(message);
+ if (ccnxControl_IsCPI(control) && ccnxControl_IsACK(control)) {
+ uint64_t sequenceNumber = ccnxControl_GetAckOriginalSequenceNumber(control);
+ if (sequenceNumber == expectedSequenceNumber) {
+ matchedSequenceNumber = true;
+ }
+ }
+ }
+ ccnxMetaMessage_Release(&message);
+ } else {
+ // this is likely some sort of error with the connection.
+ // should report this somehow. This case shows up from test_ccnx_PortalAPI.
+ result = false;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_ccnxPortal_Destroy(CCNxPortal **portalPtr)
+{
+ CCNxPortal *portal = *portalPtr;
+
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ ccnxPortalStack_Stop(portal->stack);
+ ccnxPortalStack_Release((CCNxPortalStack **) &portal->stack);
+}
+
+parcObject_ExtendPARCObject(CCNxPortal, _ccnxPortal_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortal, CCNxPortal);
+
+parcObject_ImplementRelease(ccnxPortal, CCNxPortal);
+
+CCNxPortal *
+ccnxPortal_Create(const CCNxPortalAttributes *attributes, const CCNxPortalStack *portalStack)
+{
+ CCNxPortal *result = parcObject_CreateInstance(CCNxPortal);
+
+ if (result != NULL) {
+ result->stack = portalStack;
+ result->status.eof = false;
+ result->status.error = 0;
+ }
+
+ if (ccnxPortalStack_Start(portalStack) == false) {
+ parcObject_Release((void **) &result);
+ }
+
+ return result;
+}
+
+const CCNxPortalStatus *
+ccnxPortal_GetStatus(const CCNxPortal *portal)
+{
+ return &portal->status;
+}
+
+bool
+ccnxPortal_SetAttributes(CCNxPortal *portal, const CCNxPortalAttributes *attributes)
+{
+ return ccnxPortalStack_SetAttributes(portal->stack, attributes);
+}
+
+int
+ccnxPortal_GetFileId(const CCNxPortal *portal)
+{
+ return ccnxPortalStack_GetFileId(portal->stack);
+}
+
+bool
+ccnxPortal_Listen(CCNxPortal *restrict portal, const CCNxName *restrict name, const time_t secondsToLive, const CCNxStackTimeout *microSeconds)
+{
+ bool result = ccnxPortalStack_Listen(portal->stack, name, microSeconds);
+
+ if (result == true) {
+ _ccnxPortal_SetAnchor(portal, name, secondsToLive);
+ }
+
+ portal->status.error = (result == true) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+
+ return result;
+}
+
+bool
+ccnxPortal_Ignore(CCNxPortal *portal, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ bool result = ccnxPortalStack_Ignore(portal->stack, name, microSeconds);
+
+ portal->status.error = (result == true) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+
+ return result;
+}
+
+bool
+ccnxPortal_Send(CCNxPortal *restrict portal, const CCNxMetaMessage *restrict message, const CCNxStackTimeout *timeout)
+{
+ bool result = ccnxPortalStack_Send(portal->stack, message, timeout);
+
+ portal->status.error = result ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+ return result;
+}
+
+CCNxMetaMessage *
+ccnxPortal_Receive(CCNxPortal *portal, const CCNxStackTimeout *timeout)
+{
+ CCNxMetaMessage *result = ccnxPortalStack_Receive(portal->stack, timeout);
+
+ // This modal operation of Portal is awkward.
+ // Messages are interest = content-object, while Chunked is interest = {content-object_1, content-object_2, ...}
+ // If chunked.
+ // If Content Object
+ // If this content object is the final chunk
+ // Set EOF
+
+ portal->status.error = (result != NULL) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+ return result;
+}
+
+const PARCKeyId *
+ccnxPortal_GetKeyId(const CCNxPortal *portal)
+{
+ return ccnxPortalStack_GetKeyId(portal->stack);
+}
+
+bool
+ccnxPortal_IsEOF(const CCNxPortal *portal)
+{
+ return portal->status.eof;
+}
+
+bool
+ccnxPortal_IsError(const CCNxPortal *portal)
+{
+ return portal->status.error != 0;
+}
+
+int
+ccnxPortal_GetError(const CCNxPortal *portal)
+{
+ return portal->status.error;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h
new file mode 100644
index 00000000..59711d0f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h
@@ -0,0 +1,529 @@
+/*
+ * 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_Portal.h
+ * @brief A low-level API for CCN Interests, Content Objects, and Control messages.
+ *
+ * \mainpage CCNxPortal
+ * CCNxPortal is a low-level API providing direct access to individual CCNxInterest and CCNxContentObject messages.
+ * The API provides very basic access to the "registration" operations for applications to receive CCNxInterest messages and
+ * facilities for using different, pre-configured protocol stacks.
+ *
+ * An application may have many `CCNxPortal` instances, each instance representing a particular protocol stack configuration.
+ * Normally an application uses a `CCNxPortalFactory`to create instances rather than creating `CCNxPortal` instances directly.
+ * This permits a factory to be setup to provide common attributes and configuration parameters shared by multiple `CCNxPortal`
+ * instances.
+ *
+ * The input/output functions, whether direct like `ccnxPortal_Send` and `ccnxPortal_Receive`,
+ * in indirect (such as `ccnxPortal_Listen`), take a parameter that specifiess a timeout behaviour for the function.
+ * As a result, an application may use the functions as blocking or non-blocking I/O as needed without having to use
+ * multiple `CCNxPortal` instances with different blocking or non-blocking behaviour.
+ *
+ * Specifying the timeout behaviour consists of providing a pointer to a `CCNxStackTimeout` value,
+ * or the value `CCNxStackTimeout_Never`.
+ *
+ * * `CCNxStackTimeout_Immediate`:
+ * The function returns immediately,
+ * after first attempting to perform its function provided it can complete without any blocking.
+ * For example `ccnxPortal_Receive` will return either the next `CCNxMetaMessage`,
+ * if one is waiting, or NULL indicating no message was available.
+ * The function `ccnxPortal_Send` will return after first attempting to enqueue its message on the output message queue.
+ * If the function would have to wait for space on the output message queue, then it returns indicating failure.
+ *
+ * * `CCNxStackTimeout_Microseconds()`:
+ * Functions will perform their operations blocking only for the maximum time
+ * specified.
+ *
+ * * `CCNxStackTimeout_Never`:
+ * Functions will perform their operations potentially blocking forever.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_Portal_h
+#define CCNx_Portal_API_ccnx_Portal_h
+
+struct ccnx_portal_status;
+/**
+ * @brief The status of the CCNx Portal
+ */
+typedef struct ccnx_portal_status CCNxPortalStatus;
+
+struct ccnx_portal;
+/**
+ * @brief The CCNx Portal
+ */
+typedef struct ccnx_portal CCNxPortal;
+
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_KeyId.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+/**
+ * Create a new `CCNxPortal` instance with the given {@link CCNxPortalStack}.
+ *
+ * @param [in] attributes A pointer to a valid `CCNxPortalAttributes` instance
+ * @param [in] stack A pointer to a valid `CCNxPortalStack` instance.
+ *
+ * @return non-NULL A pointer to a valid `CCNxPortal` instance that must be released via {@link ccnxPortal_Release}.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxPortal *ccnxPortal_Create(const CCNxPortalAttributes *attributes, const CCNxPortalStack *stack);
+
+/**
+ * Increase the number of references to a `CCNxPortal`.
+ *
+ * Note that new `CCNxPortal` is not created,
+ * only that the given `CCNxPortal` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ * @return The input `CCNxPortal` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortal_Create(attributes, stack);
+ *
+ * CCNxPortal *portal2 = ccnxPortal_Acquire(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * ccnxPortal_Release(&portal2);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortal_Acquire(const CCNxPortal *portal);
+
+/**
+ * Release a previously acquired reference to the specified `CCNxPortal` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] portalPtr A pointer to a pointer to a `CCNxPortal` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_CreatePortal}
+ * @see {@link ccnxPortal_Create}
+ */
+void ccnxPortal_Release(CCNxPortal **portalPtr);
+
+/**
+ * Return a pointer to the given `CCNxPortal`'s {@link CCNxPortalStatus} instance.
+ *
+ * A `CCNxPortalStatus` instance is used to extract information about the state of the open
+ * portal, e.g., whether or not an error has occurred or EOF has been reached.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return A non-null pointer to a `CCNxPortalStatus` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxPortalStatus *status = ccnxPortal_GetStatus(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+const CCNxPortalStatus *ccnxPortal_GetStatus(const CCNxPortal *portal);
+
+/**
+ * Get the underlying file descriptor for the given `CCNxPortal`.
+ *
+ * This is the operating systems file descriptor for use with read, write, close, select, poll, ioctl, and so forth.
+ *
+ * @b Users should expect that this function will be removed in favor
+ * of a more general select/poll implementation that works with instances of `CCNxPortal` as well as normal file descriptors.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return The underlying file descriptor for the given `CCNxPortal`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * int fileDescriptor = ccnxPortal_GetFile(portal);
+ *
+ * // use the fileDescriptor as necessary
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+int ccnxPortal_GetFileId(const CCNxPortal *portal);
+
+/**
+ * Set the attributes for the specified `CCNxPortal` instance.
+ *
+ * A {@link CCNxPortalAttributes} instance encapsulates information about the logging and blocked
+ * state of the `CCNxPortal` instance. These are immutable instances which are not
+ * meant to be changed. Rather, they are intended to configure the attributes
+ * of other `CCNxPortal` instances.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] attributes A pointer to a `CCNxPortalAttributes` instance that will be used.
+ *
+ * @return `true` if the attributes were successfully set, `false` otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_GetAttributes}
+ */
+bool ccnxPortal_SetAttributes(CCNxPortal *portal, const CCNxPortalAttributes *attributes);
+
+/**
+ * Listen for CCN Interests in the given {@link CCNxName}, i.e., with the given name prefix.
+ *
+ * If the local CCN router is available, this induces a route update for the given name.
+ * Messaging with the local CCN router are governed by the `CCNxPortalFactory` properties named by `CCNxPortalFactory_LocalRouterTimeout`
+ *
+ * An invocation of the function will return after the time specified by the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] name A `CCNxName` prefix used to filter and accept Interests.
+ * @param [in] secondsToLive The number of seconds for this Listen to remain active.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` The operation succeeded.
+ * @return `false` The operation failed. See {@link ccnxPortal_GetStatus}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 600, CCNxStackTimeout_MicroSeconds(5000))) {
+ * ...
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Ignore}
+ * @see {@link ccnxPortalFactory_CreatePortal}
+ */
+bool ccnxPortal_Listen(CCNxPortal *restrict portal, const CCNxName *restrict name, const time_t secondsToLive, const CCNxStackTimeout *timeout);
+
+/**
+ * Stop listening for Interests with the given {@link CCNxName}.
+ *
+ * An invocation of the function will return after the time specified by the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] name A `CCNxName` name to be ignored.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` The operation succeeded
+ * @return `false` The operation failed. See {@link CCNxPortalStatus}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ * if (ccnxPortal_Ignore(portal, name, CCNxStackTimeout_Never)) {
+ * ....
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Listen}
+ * @see {@link CCNxPortalStatus}
+ */
+bool ccnxPortal_Ignore(CCNxPortal *portal, const CCNxName *name, const CCNxStackTimeout *timeout);
+
+/**
+ * Send a {@link CCNxMetaMessage} to the protocol stack.
+ *
+ * The portal message may be an Interest, Content Object, or Control Message.
+ * The exact type wrapped by the portal message may be determined via
+ * {@link ccnxMetaMessage_IsInterest}, {@link ccnxMetaMessage_IsContentObject}, and
+ * {@link ccnxMetaMessage_IsControl}. This enables a seamless API for both
+ * both producer and consumer applications.
+ *
+ * An invocation of the function will wait for the time specified by the pointer to the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` No errors occurred.
+ * @return `false` A protocol stack error occurred while writing the message (see `ccnxPortal_GetError`).
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ *
+ * if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ * ...
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxInterest_Release(&interest);
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Receive}
+ */
+bool ccnxPortal_Send(CCNxPortal *restrict portal, const CCNxMetaMessage *restrict message, const CCNxStackTimeout *timeout);
+
+/**
+ * Read data from the protocol stack and construct a {@link CCNxMetaMessage}.
+ *
+ * The portal message may be an Interest, Content Object, or Control Message.
+ * The exact type wrapped by the portal message may be determined via
+ * {@link ccnxMetaMessage_IsInterest}, {@link ccnxMetaMessage_IsContentObject}, and
+ * {@link ccnxMetaMessage_IsControl}. This enables a seamless API for both
+ * both producer and consumer applications.
+ *
+ * An invocation of the function will wait for the time specified by the pointer to the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`.
+ *
+ * If NULL is returned, the caller may test the value of `errno` to discriminate the conditions.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return CCNxMetaMessage A `CCNxMetaMessage` instance that must be freed via {@link ccnxMetaMessage_Release}.
+ * @return NULL An error occurred while reading from the protocol stack (see `ccnxPortal_GetError`).
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ *
+ * if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ * for (int responses = 0; responses == 0;) {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * if (message != NULL) {
+ * ...
+ * }
+ * }
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxInterest_Release(&interest);
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Send}
+ * @see `ccnxMetaMessage_IsInterest`
+ * @see `ccnxMetaMessage_IsContentObject`
+ * @see `ccnxMetaMessage_IsControl`
+ */
+CCNxMetaMessage *ccnxPortal_Receive(CCNxPortal *portal, const CCNxStackTimeout *timeout);
+
+/**
+ * Get the {@link PARCKeyId} of the identity bound to the given `CCNxPortal` instance.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return The `PARCKeyId` instance associated with this `CCNxPortal`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal =
+ * ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * PARCKeyId *keyId = ccnxPortal_GetKeyId(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalFactory_CreatePortal
+ */
+const PARCKeyId *ccnxPortal_GetKeyId(const CCNxPortal *portal);
+
+/**
+ * Return `true` if the last operation induced an end-of-file state.
+ *
+ * <b>Currently this is inoperable. It's likely that the chunked mode of Portal will be deprecated and replaced at a high archtectural level.</b>
+ *
+ * This only applies to Portal instances configured for Chunked protocol.
+ * If the received chunk is equal to the currently `last chunk` this will return true.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return `true` The last operation induced an end-of-file state.
+ * @return `false` The last operation did not induce an end-of-file state.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Chunked);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isEOF = ccnxPortal_IsEOF(portal);
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+bool ccnxPortal_IsEOF(const CCNxPortal *portal);
+
+/**
+ * Return `true` if the last operation induced an error, `false` otherwise.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return `true` The last operation induced an error.
+ * @return `false` The last operation induced no error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isError = ccnxPortal_IsError(portal);
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_GetError}
+ */
+bool ccnxPortal_IsError(const CCNxPortal *portal);
+
+/**
+ * Determine the type of error, if any, that has occurred.
+ *
+ * The return value corresponds to the values of errno.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return An integer error code.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isError = ccnxPortal_IsError(portal);
+ * if (isError) {
+ * printf("Error code: %d\n", ccnxPortal_GetError(portal));
+ * }
+ *
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_IsError}
+ */
+int ccnxPortal_GetError(const CCNxPortal *portal);
+
+/**
+ * Flush the input and output paths and pause the protocol stack.
+ *
+ * The timeout value is currently not used, instead this function will block until the operation is complete.
+ *
+ * @param [in] portal A pointer to a valid instance of `CCNxPortal`.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` If successful.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortal_Flush(CCNxPortal *portal, const CCNxStackTimeout *timeout);
+
+#endif // CCNx_Portal_API_ccnx_Portal_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c
new file mode 100755
index 00000000..092e063c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Deque.h>
+
+typedef struct {
+ PARCDeque *messageAddressBuffer;
+} _CCNxPortalAPIContext;
+
+static void
+_ccnxPortalAPIContext_Destroy(_CCNxPortalAPIContext **instancePtr)
+{
+ _CCNxPortalAPIContext *instance = *instancePtr;
+
+ parcDeque_Release(&instance->messageAddressBuffer);
+}
+
+parcObject_ExtendPARCObject(_CCNxPortalAPIContext, _ccnxPortalAPIContext_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+//static parcObject_ImplementAcquire(_ccnxPortalAPIContext, _CCNxPortalAPIContext);
+
+static parcObject_ImplementRelease(_ccnxPortalAPIContext, _CCNxPortalAPIContext);
+
+static _CCNxPortalAPIContext *
+_ccnxPortalAPIContext_Create(void)
+{
+ _CCNxPortalAPIContext *result = parcObject_CreateInstance(_CCNxPortalAPIContext);
+ result->messageAddressBuffer = parcDeque_Create();
+ return result;
+}
+
+static void
+_ccnxPortalAPI_Start(void *privateData)
+{
+}
+
+static void
+_ccnxPortalAPI_Stop(void *privateData)
+{
+}
+
+static bool
+_ccnxPortalAPI_Send(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalAPIContext *transportContext = (_CCNxPortalAPIContext *) privateData;
+
+ // Save the address of the portal message on our queue. We don't need to copy the whole message.
+ parcDeque_Append(transportContext->messageAddressBuffer, (void *) ccnxMetaMessage_Acquire(portalMessage));
+
+ return true;
+}
+
+static CCNxMetaMessage *
+_ccnxPortalAPI_Receive(void *privateData, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalAPIContext *transportContext = (_CCNxPortalAPIContext *) privateData;
+
+ if (parcDeque_IsEmpty(transportContext->messageAddressBuffer)) {
+ return NULL;
+ }
+
+ CCNxMetaMessage *result = (CCNxMetaMessage *) parcDeque_RemoveFirst(transportContext->messageAddressBuffer);
+
+ return result;
+}
+
+static int
+_ccnxPortalAPI_GetFileId(void *privateData)
+{
+ return 3;
+}
+
+static CCNxPortalAttributes *
+_ccnxPortalAPI_GetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_ccnxPortalAPI_SetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ return false;
+}
+
+static bool
+_ccnxPortalAPI_Listen(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return true;
+}
+
+static bool
+_ccnxPortalAPI_Ignore(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return true;
+}
+
+CCNxPortal *
+ccnxPortalAPI_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ _CCNxPortalAPIContext *apiContext = _ccnxPortalAPIContext_Create();
+
+ CCNxPortalStack *stack =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _ccnxPortalAPI_Start,
+ _ccnxPortalAPI_Stop,
+ _ccnxPortalAPI_Receive,
+ _ccnxPortalAPI_Send,
+ _ccnxPortalAPI_Listen,
+ _ccnxPortalAPI_Ignore,
+ _ccnxPortalAPI_GetFileId,
+ _ccnxPortalAPI_SetAttributes,
+ _ccnxPortalAPI_GetAttributes,
+ apiContext,
+ (void (*)(void **))_ccnxPortalAPIContext_Release);
+
+ CCNxPortal *result = ccnxPortal_Create(attributes, stack);
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h
new file mode 100755
index 00000000..b5bf0f4c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h
@@ -0,0 +1,44 @@
+/*
+ * 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_PortalAPI.h
+ * @brief A Portal Protocol Stack implementation that simulates a real network stack.
+ *
+ * This Portal Protocol Stack implementation simulates a network stack for the purposes of testing and development.
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnxPortalAPI__
+#define __CCNx_Portal_API__ccnxPortalAPI__
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+/**
+ * Create a {@link CCNxPortal} instance from the given @p factory and @p attributes.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance
+ *
+ * @return non-null A pointer to a valid `CCNxPortal` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxPortal *ccnxPortalAPI_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnxPortalAPI__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c
new file mode 100644
index 00000000..3155823a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h>
+
+struct CCNxPortalAnchor {
+ CCNxName *prefix;
+ time_t expireTime;
+};
+
+static bool
+_ccnxPortalAnchor_Destructor(CCNxPortalAnchor **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a CCNxPortalAnchor pointer.");
+ CCNxPortalAnchor *instance = *instancePtr;
+
+ ccnxName_Release(&instance->prefix);
+
+ /* cleanup the instance fields here */
+ return true;
+}
+
+parcObject_ImplementAcquire(ccnxPortalAnchor, CCNxPortalAnchor);
+
+parcObject_ImplementRelease(ccnxPortalAnchor, CCNxPortalAnchor);
+
+#define parcObject_OverrideCopy(_name_) .copy = (PARCObjectCopy *) _name_
+parcObject_Override(CCNxPortalAnchor, PARCObject,
+ parcObject_OverrideCopy(ccnxPortalAnchor_Copy),
+ .toString = (PARCObjectToString *) ccnxPortalAnchor_ToString,
+ .equals = (PARCObjectEquals *) ccnxPortalAnchor_Equals,
+ .compare = (PARCObjectCompare *) ccnxPortalAnchor_Compare,
+ .hashCode = (PARCObjectHashCode *) ccnxPortalAnchor_HashCode,
+ .toJSON = (PARCObjectToJSON *) ccnxPortalAnchor_ToJSON,
+ .display = (PARCObjectDisplay *) ccnxPortalAnchor_Display,
+ .destructor = (PARCObjectDestructor *) _ccnxPortalAnchor_Destructor
+ );
+
+void
+ccnxPortalAnchor_AssertValid(const CCNxPortalAnchor *instance)
+{
+ assertTrue(ccnxPortalAnchor_IsValid(instance),
+ "CCNxPortalAnchor is not valid.");
+}
+
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Create(const CCNxName *name, time_t expireTime)
+{
+ CCNxPortalAnchor *result = parcObject_CreateInstance(CCNxPortalAnchor);
+
+ if (result != NULL) {
+ result->prefix = ccnxName_Acquire(name);
+ result->expireTime = expireTime;
+ }
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_CreateFromJSON(const PARCJSON *json)
+{
+ CCNxPortalAnchor *result = parcObject_CreateInstance(CCNxPortalAnchor);
+
+ if (result != NULL) {
+ result->prefix = ccnxName_CreateFromCString(parcBuffer_Overlay(parcJSONValue_GetString(parcJSON_GetByPath(json, "/namePrefix")), 0));
+ result->expireTime = parcJSONValue_GetInteger(parcJSON_GetByPath(json, "/expireTime"));
+
+ ccnxPortalAnchor_OptionalAssertValid(result);
+ }
+
+ return result;
+}
+
+int
+ccnxPortalAnchor_Compare(const CCNxPortalAnchor *instance, const CCNxPortalAnchor *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Copy(const CCNxPortalAnchor *original)
+{
+ CCNxName *prefixCopy = ccnxName_Copy(original->prefix);
+ CCNxPortalAnchor *result = ccnxPortalAnchor_Create(prefixCopy, original->expireTime);
+ ccnxName_Release(&prefixCopy);
+
+ return result;
+}
+
+void
+ccnxPortalAnchor_Display(const CCNxPortalAnchor *anchor, int indentation)
+{
+ char *prefix = ccnxName_ToString(anchor->prefix);
+
+ parcDisplayIndented_PrintLine(indentation, "CCNxPortalAnchor@%p {", anchor);
+ parcDisplayIndented_PrintLine(indentation + 1, ".prefix=%s}", prefix);
+ parcDisplayIndented_PrintLine(indentation + 1, ".expireTime=%ld", anchor->expireTime);
+
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+ parcMemory_Deallocate(&prefix);
+}
+
+bool
+ccnxPortalAnchor_Equals(const CCNxPortalAnchor *x, const CCNxPortalAnchor *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (ccnxName_Equals(x->prefix, y->prefix)) {
+ if (x->expireTime == y->expireTime) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+ccnxPortalAnchor_HashCode(const CCNxPortalAnchor *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+ccnxPortalAnchor_IsValid(const CCNxPortalAnchor *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+ccnxPortalAnchor_ToJSON(const CCNxPortalAnchor *anchor)
+{
+ ccnxPortalAnchor_OptionalAssertValid(anchor);
+
+ PARCJSON *result = parcJSON_Create();
+ if (result != NULL) {
+ char *prefix = ccnxName_ToString(anchor->prefix);
+
+ parcJSON_AddString(result, "namePrefix", prefix);
+ parcJSON_AddInteger(result, "expireTime", (int64_t) anchor->expireTime);
+
+ parcMemory_Deallocate(&prefix);
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+ccnxPortalAnchor_BuildString(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer)
+{
+ char *name = ccnxName_ToString(anchor->prefix);
+
+ char expireTime[64];
+ if (anchor->expireTime == -1) {
+ strcpy(expireTime, " never");
+ } else {
+ parcTime_TimeAsRFC3339(anchor->expireTime, expireTime);
+ }
+ parcBufferComposer_Format(composer, "{ %s %s }", name, expireTime);
+
+ parcMemory_Deallocate(&name);
+
+ return composer;
+}
+
+char *
+ccnxPortalAnchor_ToString(const CCNxPortalAnchor *anchor)
+{
+ ccnxPortalAnchor_OptionalAssertValid(anchor);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_BuildString(anchor, composer);
+ char *result = parcBufferComposer_ToString(composer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Deserialize(PARCBuffer *buffer)
+{
+ PARCJSON *json = parcJSON_ParseBuffer(buffer);
+
+ CCNxPortalAnchor *result = ccnxPortalAnchor_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ return result;
+}
+
+PARCBufferComposer *
+ccnxPortalAnchor_Serialize(const CCNxPortalAnchor *namePrefix, PARCBufferComposer *composer)
+{
+ PARCJSON *json = ccnxPortalAnchor_ToJSON(namePrefix);
+
+ char *string = parcJSON_ToString(json);
+ parcBufferComposer_PutString(composer, string);
+ parcMemory_Deallocate(&string);
+ parcJSON_Release(&json);
+ return composer;
+}
+
+CCNxName *
+ccnxPortalAnchor_GetNamePrefix(const CCNxPortalAnchor *anchor)
+{
+ return anchor->prefix;
+}
+
+time_t
+ccnxPortalAnchor_GetExpireTime(const CCNxPortalAnchor *anchor)
+{
+ return anchor->expireTime;
+}
+
+time_t
+ccnxPortalAnchor_SetExpireTime(CCNxPortalAnchor *anchor, const time_t expireTime)
+{
+ time_t previousExpireTime = anchor->expireTime;
+ anchor->expireTime = expireTime;
+ return previousExpireTime;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h
new file mode 100644
index 00000000..fbf576f2
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h
@@ -0,0 +1,396 @@
+/*
+ * 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_PortalAnchor.h
+ * @brief CCN Routing control for CCNxPortal
+ *
+ */
+#ifndef CCNxPortal_ccnx_PortalAnchor
+#define CCNxPortal_ccnx_PortalAnchor
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+struct CCNxPortalAnchor;
+typedef struct CCNxPortalAnchor CCNxPortalAnchor;
+
+/**
+ * Increase the number of references to a `CCNxPortalAnchor` instance.
+ *
+ * Note that new `CCNxPortalAnchor` is not created,
+ * only that the given `CCNxPortalAnchor` reference count is incremented.
+ * Discard the reference by invoking `ccnxPortalAnchor_Release`.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create();
+ *
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Acquire();
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Acquire(const CCNxPortalAnchor *instance);
+
+#ifdef CCNxPortal_DISABLE_VALIDATION
+# define ccnxPortalAnchor_OptionalAssertValid(_instance_)
+#else
+# define ccnxPortalAnchor_OptionalAssertValid(_instance_) ccnxPortalAnchor_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `CCNxPortalAnchor` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_AssertValid(const CCNxPortalAnchor *instance);
+
+/**
+ * Create an instance of CCNxPortalAnchor
+ *
+ * @return non-NULL A pointer to a valid CCNxPortalAnchor instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Create(const CCNxName *name, time_t expireTime);
+
+/**
+ * Create an instance of `CCNxPortalAnchor` from an instance of `PARCJSON`.
+ *
+ * @return non-NULL A pointer to a valid CCNxPortalAnchor instance.
+ * @return NULL An error occurred.
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_CreateFromJSON(const PARCJSON *json);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] other A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalAnchor_Equals
+ */
+int ccnxPortalAnchor_Compare(const CCNxPortalAnchor *instance, const CCNxPortalAnchor *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `CCNxPortalAnchor` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * CCNxPortalAnchor *copy = ccnxPortalAnchor_Copy(&b);
+ *
+ * ccnxPortalAnchor_Release(&b);
+ * ccnxPortalAnchor_Release(&copy);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Copy(const CCNxPortalAnchor *original);
+
+/**
+ * Print a human readable representation of the given `CCNxPortalAnchor`.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Display(a, 0);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_Display(const CCNxPortalAnchor *instance, int indentation);
+
+/**
+ * Determine if two `CCNxPortalAnchor` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxPortalAnchor` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `ccnxPortalAnchor_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxPortalAnchor_Equals(x, y)` must return true if and only if
+ * `ccnxPortalAnchor_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxPortalAnchor_Equals(x, y)` returns true and
+ * `ccnxPortalAnchor_Equals(y, z)` returns true,
+ * then `ccnxPortalAnchor_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxPortalAnchor_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxPortalAnchor_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] y A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ * @see ccnxPortalAnchor_HashCode
+ */
+bool ccnxPortalAnchor_Equals(const CCNxPortalAnchor *x, const CCNxPortalAnchor *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link ccnxPortalAnchor_Equals} method,
+ * then calling the {@link ccnxPortalAnchor_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link ccnxPortalAnchor_Equals} function,
+ * then calling the `ccnxPortalAnchor_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * PARCHashCode hashValue = ccnxPortalAnchor_HashCode(buffer);
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode ccnxPortalAnchor_HashCode(const CCNxPortalAnchor *instance);
+
+/**
+ * Determine if an instance of `CCNxPortalAnchor` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool ccnxPortalAnchor_IsValid(const CCNxPortalAnchor *instance);
+
+/**
+ * Release a previously acquired reference to the given `CCNxPortalAnchor` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_Release(CCNxPortalAnchor **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * PARCJSON *json = ccnxPortalAnchor_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxPortalAnchor_ToJSON(const CCNxPortalAnchor *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `CCNxPortalAnchor`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * char *string = ccnxPortalAnchor_ToString(a);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalAnchor_Display
+ */
+char *ccnxPortalAnchor_ToString(const CCNxPortalAnchor *instance);
+
+/**
+ * Append a representation of the specified `CCNxPortalAnchor` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] name A pointer to a `CCNxPortalAnchor` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_BuildString(anchor, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *ccnxPortalAnchor_BuildString(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer);
+
+CCNxPortalAnchor *ccnxPortalAnchor_Deserialize(PARCBuffer *buffer);
+
+PARCBufferComposer *ccnxPortalAnchor_Serialize(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer);
+
+CCNxName *ccnxPortalAnchor_GetNamePrefix(const CCNxPortalAnchor *anchor);
+
+time_t ccnxPortalAnchor_GetExpireTime(const CCNxPortalAnchor *anchor);
+
+time_t ccnxPortalAnchor_SetExpireTime(CCNxPortalAnchor *anchor, const time_t expireTime);
+#endif
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c
new file mode 100644
index 00000000..0b154bea
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c
@@ -0,0 +1,39 @@
+/*
+ * 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/api/ccnx_Portal/ccnx_PortalAttributes.h>
+
+struct ccnx_portal_attributes {
+ bool logging;
+};
+
+/**
+ * Non-blocking (reads)
+ */
+const CCNxPortalAttributes ccnxPortalAttributes_NonBlocking = {
+ .logging = false
+};
+
+bool
+ccnxPortalAttributes_IsLogging(const CCNxPortalAttributes *attributes)
+{
+ return attributes->logging;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h
new file mode 100755
index 00000000..1e789b62
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_PortalAttributes.h
+ * @brief Attributes related to the `CCNxPortal` instance.
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnx_PortalAttributes__
+#define __CCNx_Portal_API__ccnx_PortalAttributes__
+
+#include <stdbool.h>
+
+struct ccnx_portal_attributes;
+/**
+ * @brief The attributes for the instance of {@link CCNxPortal}
+ */
+typedef struct ccnx_portal_attributes CCNxPortalAttributes;
+
+/**
+ * Non-blocking (reads)
+ */
+extern const CCNxPortalAttributes ccnxPortalAttributes_NonBlocking;
+
+/**
+ * Return `true` if the given attributes indicate Portal Logging is enabled.
+ *
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return `true` If the given attributes indicate Portal Logging is enabled.
+ * @return `false` If the given attributes do not indicate Portal Logging is enabled.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalAttributes_IsLogging(const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnx_PortalAttributes__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c
new file mode 100755
index 00000000..be5810bd
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <sys/errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Security.h>
+
+const char *CCNxPortalFactory_LocalRouterName = "/localstack/portalFactory/LocalRouterName";
+const char *CCNxPortalFactory_LocalForwarder = "/localstack/portalFactory/LocalForwarder";
+const char *CCNxPortalFactory_LocalRouterTimeout = "/localstack/portalFactory/LocalRouterTimeout";
+
+struct CCNxPortalFactory {
+ const PARCIdentity *identity;
+ const PARCSigner *signer;
+ const PARCKeyId *keyId;
+ const CCNxPortalAttributes *attributeTemplate;
+ PARCProperties *properties;
+};
+
+static void
+_ccnxPortalFactory_Destroy(CCNxPortalFactory **factoryPtr)
+{
+ CCNxPortalFactory *factory = *factoryPtr;
+
+ parcIdentity_Release((PARCIdentity **) &factory->identity);
+
+ parcSigner_Release((PARCSigner **) &factory->signer);
+
+ parcKeyId_Release((PARCKeyId **) &factory->keyId);
+
+ parcProperties_Release(&factory->properties);
+
+ parcSecurity_Fini();
+}
+
+parcObject_ExtendPARCObject(CCNxPortalFactory, _ccnxPortalFactory_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortalFactory, CCNxPortalFactory);
+
+parcObject_ImplementRelease(ccnxPortalFactory, CCNxPortalFactory);
+
+CCNxPortalFactory *
+ccnxPortalFactory_Create(const PARCIdentity *identity)
+{
+ parcIdentity_OptionalAssertValid(identity);
+
+ parcSecurity_Init();
+ CCNxPortalFactory *result = parcObject_CreateInstance(CCNxPortalFactory);
+ if (result != NULL) {
+ result->identity = parcIdentity_Acquire(identity);
+ result->signer = parcIdentity_CreateSigner(identity);
+ result->keyId = parcSigner_CreateKeyId(result->signer);
+ result->properties = parcProperties_Create();
+
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalRouterName, "lci:/local/dcr");
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalForwarder, "tcp://127.0.0.1:9695");
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalRouterTimeout, "1000000");
+ }
+ return result;
+}
+
+const PARCIdentity *
+ccnxPortalFactory_GetIdentity(const CCNxPortalFactory *factory)
+{
+ return factory->identity;
+}
+
+const PARCKeyId *
+ccnxPortalFactory_GetKeyId(const CCNxPortalFactory *factory)
+{
+ return factory->keyId;
+}
+
+void
+ccnxPortalFactory_Display(const CCNxPortalFactory *factory, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "CCNxPortalFactory@%p {", factory);
+
+ parcIdentity_Display(factory->identity, indentation + 1);
+ parcProperties_Display(factory->properties, indentation + 1);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+CCNxPortal *
+ccnxPortalFactory_CreatePortal(const CCNxPortalFactory *factory, CCNxStackImpl *stackImplementation)
+{
+ return stackImplementation(factory, &ccnxPortalAttributes_NonBlocking);
+}
+
+PARCProperties *
+ccnxPortalFactory_GetProperties(const CCNxPortalFactory *factory)
+{
+ return factory->properties;
+}
+
+const char *
+ccnxPortalFactory_GetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict defaultValue)
+{
+ return parcProperties_GetPropertyDefault(factory->properties, name, defaultValue);
+}
+
+void
+ccnxPortalFactory_SetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict value)
+{
+ parcProperties_SetProperty(factory->properties, name, value);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h
new file mode 100755
index 00000000..e021b92d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h
@@ -0,0 +1,236 @@
+/*
+ * 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_PortalFactory.h
+ * @brief An API for creating Portals.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_PortalFactory_h
+#define CCNx_Portal_API_ccnx_PortalFactory_h
+
+struct CCNxPortalFactory;
+/**
+ * @typedef CCNxPortalFactory
+ * @brief A Portal factory.
+ */
+typedef struct CCNxPortalFactory CCNxPortalFactory;
+
+#include <parc/algol/parc_Properties.h>
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_KeyId.h>
+
+#include <ccnx/transport/common/transport.h>
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+extern const char *CCNxPortalFactory_LocalRouterName;
+extern const char *CCNxPortalFactory_LocalForwarder;
+extern const char *CCNxPortalFactory_LocalRouterTimeout;
+
+/**
+ * Create a `CCNxPortalFactory` with the given {@link PARCIdentity}.
+ *
+ * If successful, a new reference to the given `PARCIdentity`
+ * instance is acquired and released when the result is eventually released
+ * via {@link ccnxPortalFactory_Release}.
+ * The caller must release its original reference.
+ *
+ * The given `PARCIdentity` is the identity used for interacting with the Transport Framework when creating a new stack.
+ * The default behaviour is that identity is also used for subsequent Content Object signing operations.
+ * It is permissable, however, to set a different identity,
+ * after a Portal API instance is created should its associated Transport Stack support setting a new identity.
+ *
+ * @param [in] identity A pointer to a `PARCIdentity` instance.
+ *
+ * @return non-NULL A pointer to a `CCNxPortalFactory` instance.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * char *subjectName = "An Example";
+ * char *keystoreName = "keystore";
+ * char *keystorePassword = "password";
+ *
+ * bool success = parcPkcs12KeyStore_CreateFile(keystoreName, keystorePassword, subjectName, 1024, 30);
+ *
+ * PARCIdentity *identity =
+ * parcIdentity_Create(parcIdentityFile_Create(keystoreName, keystorePassword), PARCIdentityFileAsPARCIdentity);
+ *
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ * parcIdentity_Release(&identity);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Acquire}
+ * @see {@link ccnxPortalFactory_Release}
+ */
+CCNxPortalFactory *ccnxPortalFactory_Create(const PARCIdentity *identity);
+
+/**
+ * Print a human readable representation of the given `CCNxPortalFactory` instance.
+ *
+ * @param [in] factory A pointer to the instance of `CCNxPortalFactory` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * ccnxPortalFactory_Display(0, factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ */
+void ccnxPortalFactory_Display(const CCNxPortalFactory *factory, int indentation);
+
+/**
+ * Increase the number of references to a `CCNxPortalFactory` instance.
+ *
+ * Note that new `CCNxPortalFactory` is not created,
+ * only that the given `CCNxPortalFactory` reference count is incremented.
+ * Discard the reference by invoking `ccnxPortalFactory_Release`.
+ *
+ * @param [in] instance A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *x = ccnxPortalFactory_Create(...);
+ *
+ * CCNxPortalFactory *x2 = ccnxPortalFactory_Acquire(x);
+ *
+ * ccnxPortalFactory_Release(&x);
+ * ccnxPortalFactory_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Release}
+ */
+CCNxPortalFactory *ccnxPortalFactory_Acquire(const CCNxPortalFactory *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] factoryPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ */
+void ccnxPortalFactory_Release(CCNxPortalFactory **factoryPtr);
+
+/**
+ * Get the {@link PARCIdentity} associated with the given `CCNxPortalFactory`.
+ *
+ * Note: a handle to the instance is not acquired, so you must not release it.
+ *
+ * @param [in] factory A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return A pointer to the internal `PARCIdentity` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * PARCIdentity *identity = ccnxPortalFactory_GetIdentity(factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Create}
+ */
+const PARCIdentity *ccnxPortalFactory_GetIdentity(const CCNxPortalFactory *factory);
+
+/**
+ * Get the `{@link PARCKeyId} of the {@link PARCIdentity} bound to the given CCNxPortalFactory.
+ *
+ * @param [in] factory A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return A pointer to the internal `PARCKeyId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * PARCKeyId *keyId = ccnxPortalFactory_GetKeyId(factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Create}
+ */
+const PARCKeyId *ccnxPortalFactory_GetKeyId(const CCNxPortalFactory *factory);
+
+/**
+ * @typedef CCNxStackImpl
+ * @brief A function that creates a `CCNxPortal` given a factory and attributes.
+ */
+typedef CCNxPortal *(CCNxStackImpl)(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Create an {@link CCNxPortal} instance of the specified communication type, protocol and attributes.
+ *
+ * @param [in] factory A pointer to a CCNxPortal factory to use to create the instance.
+ * @param [in,out] stackImplementation A pointer to a function initializing the protocol implementation.
+ *
+ * @return NULL An error occurred in creating the instance. See the value of `errno`
+ * @return non-NULL A pointer to a valid `CCNxPortal` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Release}
+ */
+CCNxPortal *ccnxPortalFactory_CreatePortal(const CCNxPortalFactory *factory, CCNxStackImpl *stackImplementation);
+
+PARCProperties *ccnxPortalFactory_GetProperties(const CCNxPortalFactory *factory);
+
+const char *ccnxPortalFactory_GetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict defaultValue);
+
+void ccnxPortalFactory_SetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict value);
+
+#endif // CCNx_Portal_API_ccnx_Portal_h
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c
new file mode 100755
index 00000000..f032e2c8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c
@@ -0,0 +1,452 @@
+/*
+ * 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 <sys/errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <poll.h>
+#include <stdio.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/api/control/cpi_Forwarding.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <ccnx/transport/common/ccnx_StackConfig.h>
+#include <ccnx/transport/common/ccnx_ConnectionConfig.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+
+#include <ccnx/transport/transport_rta/config/config_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/config/config_ApiConnector.h>
+#include <ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h>
+#include <ccnx/transport/transport_rta/config/config_Codec_Tlv.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Local.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Metis.h>
+#include <ccnx/transport/transport_rta/config/config_PublicKeySigner.h>
+
+static const uint16_t ccnxPortal_MetisPort = 9695;
+
+typedef enum {
+ ccnxPortalTypeChunked,
+ ccnxPortalTypeMessage
+} _CCNxPortalType;
+
+typedef enum {
+ CCNxPortalProtocol_RTALoopback,
+ ccnxPortalProtocol_RTA,
+ CCNxPortalProtocol_APILoopback
+} _CCNxPortalProtocol;
+
+typedef struct _CCNxPortalRTAContext {
+ RTATransport *rtaTransport;
+ const CCNxTransportConfig *(*createTransportConfig)(const CCNxPortalFactory *, _CCNxPortalType, _CCNxPortalProtocol);
+ const CCNxTransportConfig *configuration;
+ int fileId;
+ PARCLog *logger;
+} _CCNxPortalRTAContext;
+
+static void
+_ccnxPortalRTAContext_Destroy(_CCNxPortalRTAContext **instancePtr)
+{
+ _CCNxPortalRTAContext *instance = *instancePtr;
+
+ rtaTransport_Close(instance->rtaTransport, instance->fileId);
+ rtaTransport_Destroy(&instance->rtaTransport);
+
+ ccnxTransportConfig_Destroy((CCNxTransportConfig **) &instance->configuration);
+ parcLog_Release(&instance->logger);
+}
+
+parcObject_ExtendPARCObject(_CCNxPortalRTAContext, _ccnxPortalRTAContext_Destroy,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+static parcObject_ImplementRelease(_ccnxPortalRTAContext, _CCNxPortalRTAContext);
+
+static _CCNxPortalRTAContext *
+_ccnxPortalRTAContext_Create(RTATransport *rtaTransport, const CCNxTransportConfig *configuration, int fileId)
+{
+ _CCNxPortalRTAContext *result = parcObject_CreateInstance(_CCNxPortalRTAContext);
+ if (result != NULL) {
+ result->rtaTransport = rtaTransport;
+ result->configuration = configuration;
+ result->fileId = fileId;
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ result->logger = parcLog_Create(NULL, "ccnxPortalRTA", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+ parcLog_SetLevel(result->logger, PARCLogLevel_Debug);
+ }
+
+ return result;
+}
+
+static void
+_ccnxPortalProtocol_RTALoopback(CCNxConnectionConfig *connConfig, CCNxStackConfig *stackConfig, PARCArrayList *listOfComponentNames)
+{
+ char *bentPipeNameEnv = getenv("BENT_PIPE_NAME");
+ if (bentPipeNameEnv != NULL) {
+ } else {
+ printf("The BENT_PIPE_NAME environment variable needs to the name of a 'fifo' file. Try /tmp/test_ccnx_Portal\n");
+ }
+
+ parcArrayList_Add(listOfComponentNames, (char *) tlvCodec_GetName());
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+
+ parcArrayList_Add(listOfComponentNames, (char *) localForwarder_GetName());
+ localForwarder_ProtocolStackConfig(stackConfig);
+ localForwarder_ConnectionConfig(connConfig, bentPipeNameEnv);
+}
+
+static void
+_ccnxPortalProtocol_RTAMetis(CCNxConnectionConfig *connConfig, CCNxStackConfig *stackConfig, PARCArrayList *listOfComponentNames)
+{
+ uint16_t metisPort = ccnxPortal_MetisPort;
+ char *metisPortEnv = getenv("METIS_PORT");
+ if (metisPortEnv != NULL) {
+ metisPort = (uint16_t) atoi(metisPortEnv);
+ }
+ parcArrayList_Add(listOfComponentNames, (char *) tlvCodec_GetName());
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+
+ parcArrayList_Add(listOfComponentNames, (char *) metisForwarder_GetName());
+ metisForwarder_ProtocolStackConfig(stackConfig);
+ metisForwarder_ConnectionConfig(connConfig, metisPort);
+}
+
+/**
+ * This composes a CCNxTransportConfig instance that describes a complete transport stack assembly.
+ */
+static const CCNxTransportConfig *
+_createTransportConfig(const CCNxPortalFactory *factory, _CCNxPortalType type, _CCNxPortalProtocol protocol)
+{
+ if (type == ccnxPortalTypeChunked) {
+ // Good.
+ } else if (type == ccnxPortalTypeMessage) {
+ // Good.
+ } else {
+ return NULL;
+ }
+
+ // TODO: This is in need of some narrative of what's going on here.
+
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ PARCArrayList *listOfComponentNames = parcArrayList_Create_Capacity(NULL, NULL, 8);
+
+ parcArrayList_Add(listOfComponentNames, (char *) apiConnector_GetName());
+
+ apiConnector_ProtocolStackConfig(stackConfig);
+ apiConnector_ConnectionConfig(connConfig);
+
+ if (type == ccnxPortalTypeChunked) {
+ parcArrayList_Add(listOfComponentNames, (char *) vegasFlowController_GetName());
+ vegasFlowController_ProtocolStackConfig(stackConfig);
+ vegasFlowController_ConnectionConfig(connConfig);
+ }
+
+ switch (protocol) {
+ case CCNxPortalProtocol_RTALoopback:
+ _ccnxPortalProtocol_RTALoopback(connConfig, stackConfig, listOfComponentNames);
+ break;
+
+ case ccnxPortalProtocol_RTA:
+ _ccnxPortalProtocol_RTAMetis(connConfig, stackConfig, listOfComponentNames);
+ break;
+
+ default:
+ errno = EPROTOTYPE;
+ assertTrue(0, "Unknown protocol type: %d", protocol);
+ }
+
+
+ protocolStack_ComponentsConfigArrayList(stackConfig, listOfComponentNames);
+ parcArrayList_Destroy(&listOfComponentNames);
+
+ const PARCIdentity *identity = ccnxPortalFactory_GetIdentity(factory);
+
+ configPublicKeySigner_SetIdentity(connConfig, identity);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+
+ ccnxStackConfig_Release(&stackConfig);
+
+ return result;
+}
+
+static void
+_ccnxPortalRTA_Start(void *privateData)
+{
+}
+
+static void
+_ccnxPortalRTA_Stop(void *privateData)
+{
+}
+
+static bool
+_ccnxPortalRTA_Send(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ bool result = rtaTransport_Send(transportContext->rtaTransport, transportContext->fileId, portalMessage, microSeconds);
+
+ return result;
+}
+
+static CCNxMetaMessage *
+_ccnxPortalRTA_Receive(void *privateData, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ CCNxMetaMessage *result = NULL;
+
+ TransportIOStatus status = rtaTransport_Recv(transportContext->rtaTransport, transportContext->fileId, &result, microSeconds);
+
+ if (status != TransportIOStatus_Success) {
+ return NULL;
+ }
+
+ return result;
+}
+
+static int
+_ccnxPortalRTA_GetFileId(void *privateData)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ return transportContext->fileId;
+}
+
+static CCNxPortalAttributes *
+_ccnxPortalRTA_GetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_nonBlockingPortal(const _CCNxPortalRTAContext *transportContext)
+{
+ int fd = transportContext->fileId;
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, NULL)) != -1) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+_ccnxPortalRTA_SetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ bool result = _nonBlockingPortal(transportContext);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_Listen(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+
+ ccnxControl_Release(&control);
+
+ bool result = _ccnxPortalRTA_Send(privateData, message, CCNxStackTimeout_Never);
+
+ // There is a problem here if the client invokes this function on a portal that is already receiving messages.
+ // This simply absorbs messages until the receipt of the acknowledgement of this listen.
+ // Perhaps what should happen is not read any messages and let the client sort it out in its read loop.
+ if (result == true) {
+ CCNxMetaMessage *response = _ccnxPortalRTA_Receive(privateData, microSeconds);
+
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ // TODO: Check that the response was success.
+ result = true;
+ }
+ ccnxMetaMessage_Release(&response);
+ } else {
+ // We got a NULL reponse (possibly due to timeout). Since we always expect a
+ // response from the forwarder, consider this a failure.
+ result = false;
+ }
+ }
+
+ ccnxMetaMessage_Release(&message);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_Ignore(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+ ccnxControl_Release(&control);
+
+ bool result = _ccnxPortalRTA_Send(privateData, message, CCNxStackTimeout_Never);
+
+ // There is a problem here if the client invokes this function on a portal that is already receiving messages.
+ // This simply absorbs messages until the receipt of the acknowledgement of this listen.
+ // Perhaps what should happen is not read any messages and let the client sort it out in its read loop.
+ if (result == true) {
+ CCNxMetaMessage *response = _ccnxPortalRTA_Receive(privateData, microSeconds);
+
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ // TODO: Check that the response was success.
+ result = true;
+ }
+ ccnxMetaMessage_Release(&response);
+ } else {
+ // We got a NULL reponse (possibly due to timeout). Since we always expect a
+ // response from the forwarder, consider this a failure.
+ result = false;
+ }
+ }
+
+ ccnxMetaMessage_Release(&message);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_IsConnected(CCNxPortal *portal)
+{
+ bool result = false;
+
+ CCNxMetaMessage *response;
+
+ if ((response = ccnxPortal_Receive(portal, CCNxStackTimeout_Never)) != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ CCNxControl *control = ccnxMetaMessage_GetControl(response);
+
+ if (ccnxControl_IsNotification(control)) {
+ NotifyStatus *status = ccnxControl_GetNotifyStatus(control);
+
+ if (notifyStatus_IsConnectionOpen(status) == true) {
+ result = true;
+ }
+ notifyStatus_Release(&status);
+ }
+ }
+ ccnxMetaMessage_Release(&response);
+ }
+
+ return result;
+}
+
+static CCNxPortal *
+_ccnxPortalRTA_CreatePortal(const CCNxPortalFactory *factory,
+ _CCNxPortalType type,
+ _CCNxPortalProtocol protocol,
+ const CCNxPortalAttributes *attributes)
+{
+ CCNxPortal *result = NULL;
+
+ const CCNxTransportConfig *configuration = _createTransportConfig(factory, type, protocol);
+
+ if (ccnxTransportConfig_IsValid(configuration) == false) {
+ return NULL;
+ }
+
+ RTATransport *rtaTransport = rtaTransport_Create();
+ if (rtaTransport != NULL) {
+ int fileDescriptor = rtaTransport_Open(rtaTransport, (CCNxTransportConfig *) configuration);
+
+ _CCNxPortalRTAContext *transportContext = _ccnxPortalRTAContext_Create(rtaTransport, configuration, fileDescriptor);
+
+ if (transportContext != NULL) {
+ CCNxPortalStack *implementation =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _ccnxPortalRTA_Start,
+ _ccnxPortalRTA_Stop,
+ _ccnxPortalRTA_Receive,
+ _ccnxPortalRTA_Send,
+ _ccnxPortalRTA_Listen,
+ _ccnxPortalRTA_Ignore,
+ _ccnxPortalRTA_GetFileId,
+ _ccnxPortalRTA_SetAttributes,
+ _ccnxPortalRTA_GetAttributes,
+ transportContext,
+ (void (*)(void **))_ccnxPortalRTAContext_Release);
+
+ result = ccnxPortal_Create(attributes, implementation);
+
+ if (result != NULL) {
+ if (_ccnxPortalRTA_IsConnected(result) == true) {
+ _nonBlockingPortal(transportContext);
+ } else {
+ ccnxPortal_Release(&result);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+CCNxPortal *
+ccnxPortalRTA_Message(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeMessage, ccnxPortalProtocol_RTA, attributes);
+}
+
+CCNxPortal *
+ccnxPortalRTA_Chunked(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeChunked, ccnxPortalProtocol_RTA, attributes);
+}
+
+CCNxPortal *
+ccnxPortalRTA_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeMessage, CCNxPortalProtocol_RTALoopback, attributes);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h
new file mode 100755
index 00000000..157ad203
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h
@@ -0,0 +1,82 @@
+/*
+ * 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_PortalRTA.h
+ * @brief The CCNxPortalStack representation of an "RTA" Transport Stack
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnx_PortalRTA__
+#define __CCNx_Portal_API__ccnx_PortalRTA__
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for Message-by-Message interaction.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_Message(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for Chunked interaction.
+ *
+ * The flow of inbound Content Objects is initiated by the first `CCNxInterest` specifying a valid Chunked protocol.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Chunked);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_Chunked(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for a loopback, Message-by-Message interaction.
+ *
+ * The loopback causes all messages sent to be reflected back to be received.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnx_PortalRTA__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c
new file mode 100755
index 00000000..5490c44d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <sys/errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct CCNxPortalStack {
+ CCNxPortalFactory *factory;
+
+ const CCNxPortalAttributes *attributes;
+
+ void *privateData;
+
+ void (*start)(void *privateData);
+
+ void (*stop)(void *privateData);
+
+ CCNxMetaMessage *(*read)(void *privateData, const CCNxStackTimeout *microSeconds);
+
+ bool (*write)(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds);
+
+ bool (*listen)(void *privateData, const CCNxName *restrict name, const CCNxStackTimeout *microSeconds);
+
+ bool (*ignore)(void *privateData, const CCNxName *restrict name, const CCNxStackTimeout *microSeconds);
+
+ int (*getFileId)(void *privateData);
+
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes);
+
+ CCNxPortalAttributes * (*getAttributes)(void *privateData);
+
+ void (*releasePrivateData)(void **privateData);
+};
+
+static void
+_destroy(CCNxPortalStack **instancePtr)
+{
+ CCNxPortalStack *instance = *instancePtr;
+
+ if (instance->privateData != NULL) {
+ instance->releasePrivateData(&instance->privateData);
+ }
+
+ ccnxPortalFactory_Release(&instance->factory);
+}
+
+parcObject_ExtendPARCObject(CCNxPortalStack, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortalStack, CCNxPortalStack);
+
+parcObject_ImplementRelease(ccnxPortalStack, CCNxPortalStack);
+
+CCNxPortalStack *
+ccnxPortalStack_Create(const CCNxPortalFactory *factory,
+ const CCNxPortalAttributes *attributes,
+ void (*start)(void *privateData),
+ void (*stop)(void *privateData),
+ CCNxMetaMessage *(*receive)(void *privateData, const CCNxStackTimeout *microSeconds),
+ bool (*send)(void *privateData, const CCNxMetaMessage *message, const CCNxStackTimeout *microSeconds),
+ bool (*listen)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ bool (*ignore)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ int (*getFileId)(void *privateData),
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes),
+ CCNxPortalAttributes * (*getAttributes)(void *privateData),
+ void *privateData,
+ void (*releasePrivateData)(void **privateData))
+{
+ CCNxPortalStack *result = parcObject_CreateInstance(CCNxPortalStack);
+
+ if (result != NULL) {
+ result->factory = ccnxPortalFactory_Acquire(factory);
+ result->attributes = attributes;
+ result->start = start;
+ result->stop = stop;
+ result->read = receive;
+ result->write = send;
+ result->getFileId = getFileId;
+ result->listen = listen;
+ result->ignore = ignore;
+ result->setAttributes = setAttributes;
+ result->getAttributes = getAttributes;
+ result->privateData = privateData;
+ result->releasePrivateData = releasePrivateData;
+ }
+ return result;
+}
+
+bool
+ccnxPortalStack_Start(const CCNxPortalStack *portalStack)
+{
+ portalStack->start(portalStack->privateData);
+ return true;
+}
+
+bool
+ccnxPortalStack_Stop(const CCNxPortalStack *portalStack)
+{
+ portalStack->stop(portalStack->privateData);
+ return true;
+}
+
+CCNxMetaMessage *
+ccnxPortalStack_Receive(const CCNxPortalStack *restrict portalStack, const CCNxStackTimeout *microSeconds)
+{
+ CCNxMetaMessage *result = portalStack->read(portalStack->privateData, microSeconds);
+
+ return result;
+}
+
+bool
+ccnxPortalStack_Send(const CCNxPortalStack *portalStack, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->write(portalStack->privateData, portalMessage, microSeconds);
+}
+
+bool
+ccnxPortalStack_SetAttributes(const CCNxPortalStack *portalStack, const CCNxPortalAttributes *attributes)
+{
+ return portalStack->setAttributes(portalStack->privateData, attributes);
+}
+
+bool
+ccnxPortalStack_Listen(const CCNxPortalStack *portalStack, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->listen(portalStack->privateData, name, microSeconds);
+}
+
+bool
+ccnxPortalStack_Ignore(const CCNxPortalStack *portalStack, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->ignore(portalStack->privateData, name, microSeconds);
+}
+
+int
+ccnxPortalStack_GetErrorCode(const CCNxPortalStack *portalStack)
+{
+#ifndef _ANDROID_
+ extern int errno;
+#endif
+ return errno;
+}
+
+const CCNxPortalAttributes *
+ccnxPortalStack_GetAttributes(const CCNxPortalStack *portalStack)
+{
+ return portalStack->attributes;
+}
+
+int
+ccnxPortalStack_GetFileId(const CCNxPortalStack *portalStack)
+{
+ return portalStack->getFileId(portalStack->privateData);
+}
+
+const PARCKeyId *
+ccnxPortalStack_GetKeyId(const CCNxPortalStack *portalStack)
+{
+ return ccnxPortalFactory_GetKeyId(portalStack->factory);
+}
+
+PARCProperties *
+ccnxPortalStack_GetProperties(const CCNxPortalStack *portalStack)
+{
+ return ccnxPortalFactory_GetProperties(portalStack->factory);
+}
+
+const char *
+ccnxPortalStack_GetProperty(const CCNxPortalStack *portalStack, const char *restrict name, const char *restrict defaultValue)
+{
+ return ccnxPortalFactory_GetProperty(portalStack->factory, name, defaultValue);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h
new file mode 100755
index 00000000..b119213a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h
@@ -0,0 +1,330 @@
+/*
+ * 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_PortalStack.h
+ * @brief A polymorphic interface to different Portal Stack implementations.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_PortalImplementation_h
+#define CCNx_Portal_API_ccnx_PortalImplementation_h
+
+struct CCNxPortalStack;
+/**
+ * @typedef CCNxPortalStack
+ * @brief A set of functions and state for the Portal instance.
+ */
+typedef struct CCNxPortalStack CCNxPortalStack;
+
+#include <parc/algol/parc_Properties.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+/**
+ * Create function for a `CCNxPortalStack`
+ *
+ * @param [in] factory An instance of a {@link CCNxPortalFactory}.
+ * @param [in] start A pointer to a function that takes `*privateData` as a parameter.
+ * @param [in] stop A pointer to a function that takes `*privateData` as a parameter.
+ * @param [in] receiveFunction A pointer to a function that takes `*privateData` as a parameter and returns a pointer to a {@link CCNxMetaMessage}.
+ * @param [in] send A pointer to a function that takes `*privateData` and `*portalMessage` as parameters.
+ * @param [in] listen A pointer to a function that takes `*privateData` and a {@link CCNxName} as parameters.
+ * @param [in] ignore A pointer to a function that takes `*privateData` and a {@link CCNxName} as parameters.
+ * @param [in] getFileId A pointer to a function that takes `*privateData` as a parameter and returns an `int`.
+ * @param [in] setAttributes A pointer to a function that takes `*privateData` and a {@link CCNxPortalAttributes} as parameters.
+ * @param [in] getAttributes A pointer to a function that takes `*privateData` as a parameter and returns an instance of `CCNxPortalAttributes`.
+ * @param [in] privateData A pointer to some data.
+ * @param [in] releasePrivateData A pointer to a function that takes `**privateData` as a parameter.
+ *
+ * @return A pointer to a new `CCNxPortalStack`.
+ *
+ */
+CCNxPortalStack *
+ccnxPortalStack_Create(const CCNxPortalFactory *factory,
+ const CCNxPortalAttributes *attributes,
+ void (*start)(void *privateData),
+ void (*stop)(void *privateData),
+ CCNxMetaMessage *(*receive)(void *privateData, const CCNxStackTimeout *microSeconds),
+ bool (*send)(void *privateData, const CCNxMetaMessage *message, const CCNxStackTimeout *microSeconds),
+ bool (*listen)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ bool (*ignore)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ int (*getFileId)(void *privateData),
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes),
+ CCNxPortalAttributes * (*getAttributes)(void *privateData),
+ void *privateData,
+ void (*releasePrivateData)(void **privateData));
+
+/**
+ * Increase the number of references to a `PARCBuffer`.
+ *
+ * Note that new `PARCBuffer` is not created,
+ * only that the given `PARCBuffer` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] portal A pointer to a valid CCNxPortalStack instance.
+ *
+ * @return The input `CCNxPortalStack` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *x = parcBuffer_Allocate(10);
+ *
+ * PARCBuffer *x_2 = parcBuffer_Acquire(x);
+ *
+ * parcBuffer_Release(&x);
+ * parcBuffer_Release(&x_2);
+ * }
+ * @endcode
+ */
+CCNxPortalStack *ccnxPortalStack_Acquire(const CCNxPortalStack *portal);
+
+/**
+ * Release a previously acquired reference to the specified `CCNxPortalStack` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] portalPtr A pointer to a pointer to a `CCNxPortalStack` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalStack *stack = ccnxPortalStack_Create(...);
+ *
+ * ccnxPortalStack_Release(&stack);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalStack_Create}
+ * @see {@link ccnxPortalStack_Acquire}
+ */
+void ccnxPortalStack_Release(CCNxPortalStack **portalPtr);
+
+/**
+ * Release a `CCNxPortalStack` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `CCNxPortalStack`.
+ *
+ * @param [in,out] instancePtr is a pointer to the `CCNxPortalStack` reference to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxPortalStack_Release(CCNxPortalStack **instancePtr);
+
+/**
+ * Start a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`
+ *
+ * @return `true` if stack started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Start(const CCNxPortalStack *implementation);
+
+/**
+ * Stop a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`
+ *
+ * @return `true` if stack started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Stop(const CCNxPortalStack *implementation);
+
+/**
+ * Receive a message from a `CCNxPortalStack`
+ *
+ * @param [in] portalStack A pointer to an instance of `CCNxPortalStack`
+ * @param [in] microSeconds A pointer to a `struct timeval` or NULL indicating no timeout.
+ *
+ * @return An instance of {@link CCNxMetaMessage}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxMetaMessage *ccnxPortalStack_Receive(const CCNxPortalStack *portalStack, const CCNxStackTimeout *microSeconds);
+
+/**
+ * Send a message through a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] portalMessage A pointer to an instance of `CCNxMetaMessage` to send.
+ *
+ * @return `true` if message sent successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Send(const CCNxPortalStack *implementation, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds);
+
+/**
+ * Set the attributes on a `CCNxPortalStack`.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] attributes A pointer to an instance of `CCNxPortalAttributes`.
+ * @return `true` if attributes set successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+bool ccnxPortalStack_SetAttributes(const CCNxPortalStack *implementation, const CCNxPortalAttributes *attributes);
+
+/**
+ * Get the attributes from a `CCNxPortalStack`.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @return A pointer to an instance of `CCNxPortalAttributes` associated with the @p implementation.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CCNxPortalAttributes *ccnxPortalStack_GetAttributes(const CCNxPortalStack *implementation);
+
+/**
+ * Listen for @p name on the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] name A pointer to an instance of {@link CCNxName} to listen for.
+ *
+ * @return `true` if listen started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Listen(const CCNxPortalStack *implementation, const CCNxName *name, const CCNxStackTimeout *microSeconds);
+/**
+ * Ignore (stop listening for) @p name on the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] name A pointer to an instance of {@link CCNxName} to listen for.
+ *
+ * @return `true` if ignore was successful, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+bool ccnxPortalStack_Ignore(const CCNxPortalStack *implementation, const CCNxName *name, const CCNxStackTimeout *microSeconds);
+/**
+ * Get the file ID for @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return `int` The file ID.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxPortalStack_GetFileId(const CCNxPortalStack *implementation);
+
+/**
+ * Get the {@link PARCKeyId} associated with the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return A pointer to the `PARCKeyId`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKeyId *ccnxPortalStack_GetKeyId(const CCNxPortalStack *implementation);
+
+/**
+ * Get the error code for the most recent operation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return A value corresponding to the UNIX `errno` see `sys/errno.h`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int ccnxPortalStack_GetErrorCode(const CCNxPortalStack *implementation);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCProperties *ccnxPortalStack_GetProperties(const CCNxPortalStack *portalStack);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] portalStack <#description#>
+ * @param [in] name <#description#>
+ * @param [in] defaultValue <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *ccnxPortalStack_GetProperty(const CCNxPortalStack *portalStack, const char *restrict name, const char *restrict defaultValue);
+#endif
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore
new file mode 100644
index 00000000..ebc1afaf
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore
@@ -0,0 +1,5 @@
+ccnx-portal-read
+ccnx-portal-write
+*.o
+ccnx_server
+ccnx_client
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt
new file mode 100644
index 00000000..6d0a3f09
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(CCNX_CLIENT_SRC
+ ccnx-client.c
+ ccnxPortalClient_About.c
+ )
+
+set(CCNX_SERVER_SRC
+ ccnx-server.c
+ ccnxPortalServer_About.c
+ )
+
+
+
+add_executable(ccnx-client ${CCNX_CLIENT_SRC})
+target_link_libraries(ccnx-client ${CCNX_LINK_LIBRARIES})
+
+add_executable(ccnx-server ${CCNX_SERVER_SRC})
+target_link_libraries(ccnx-server ${CCNX_LINK_LIBRARIES})
+
+install(TARGETS ccnx-client ccnx-server RUNTIME DESTINATION bin )
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c
new file mode 100755
index 00000000..dfd5d5ba
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c
@@ -0,0 +1,159 @@
+/*
+ * 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 <unistd.h>
+#include <getopt.h>
+
+#include <LongBow/runtime.h>
+
+#include "ccnxPortalClient_About.h"
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_InputStream.h>
+#include <parc/algol/parc_OutputStream.h>
+
+int
+ccnGet(PARCIdentity *identity, CCNxName *name)
+{
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ while (ccnxPortal_IsError(portal) == false) {
+ CCNxMetaMessage *response = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsContentObject(response)) {
+ CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(response);
+
+ PARCBuffer *payload = ccnxContentObject_GetPayload(contentObject);
+
+ size_t length = parcBuffer_Remaining(payload);
+ ssize_t nwritten = write(1, parcBuffer_Overlay(payload, length), length);
+ assertTrue(nwritten == length, "Did not write whole buffer, got %zd expected %zu", nwritten, length);
+
+ break;
+ }
+ ccnxMetaMessage_Release(&response);
+ }
+ }
+ }
+
+ ccnxPortal_Release(&portal);
+
+ ccnxPortalFactory_Release(&factory);
+
+ return 0;
+}
+
+void
+usage(void)
+{
+ printf("%s\n", ccnxPortalClientAbout_About());
+ printf("ccn-client --identity <file> --password <password> <objectName>\n");
+ printf("ccn-client [-h | --help]\n");
+ printf("ccn-client [-v | --version]\n");
+ printf("\n");
+ printf(" --identity The file name containing a PKCS12 keystore\n");
+ printf(" --password The password to unlock the keystore\n");
+ printf(" <objectName> The LCI name of the object to fetch\n");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFile = NULL;
+ char *keystorePassword = NULL;
+
+ /* options descriptor */
+ static struct option longopts[] = {
+ { "identity", required_argument, NULL, 'f' },
+ { "password", required_argument, NULL, 'p' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "fphv", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'f':
+ keystoreFile = optarg;
+ break;
+
+ case 'p':
+ keystorePassword = optarg;
+ break;
+
+ case 'v':
+ printf("%s\n", ccnxPortalClientAbout_Version());
+ return 0;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argv[0] == NULL || keystoreFile == NULL || keystorePassword == NULL) {
+ usage();
+ return -1;
+ }
+
+ char *objectName = argv[0];
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFile, keystorePassword);
+ if (parcIdentityFile_Exists(identityFile) == false) {
+ printf("Inaccessible keystore file '%s'.\n", keystoreFile);
+ exit(1);
+ }
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ CCNxName *name = ccnxName_CreateFromCString(objectName);
+
+ int result = ccnGet(identity, name);
+
+ parcIdentity_Release(&identity);
+ ccnxName_Release(&name);
+
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c
new file mode 100644
index 00000000..215d9019
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySignerPkcs12Store.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_SignedInfo.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_TimeStamp.h>
+
+PARCIdentity *
+getIdentity_FromFile(const char *keystoreFileName, const char *password)
+{
+ PARCIdentity *result = NULL;
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFileName, password);
+ if (identityFile != NULL) {
+ result = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+ }
+
+ return result;
+}
+
+int
+reader_writer(CCNxPortalFactory *factory, const char *uri)
+{
+ CCNxPortal *portal = ccnxPortalFactory_GetInstance(factory, ccnxPortalTypeDatagram, ccnxPortalProtocol_TLV, &ccnxPortalAttributes_Blocking);
+
+ CCNxName *prefix = ccnxName_CreateFromURI(uri);
+ CCNxName *bye = ccnxName_CreateFromURI("lci:/Hello/Goodbye%21");
+ CCNxName *contentname = ccnxName_CreateFromURI("lci:/Hello/World");
+
+ if (ccnxPortal_Listen(portal, prefix, 365 * 86400, CCNxStackTimeout_Never)) {
+ CCNxMetaMessage *msg;
+
+ while ((msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never)) != NULL) {
+ if (ccnxMetaMessage_IsInterest(msg)) {
+ CCNxInterest *interest = ccnxMetaMessage_GetInterest(msg);
+
+ CCNxName *interestName = ccnxInterest_GetName(interest);
+
+ if (ccnxName_Equals(interestName, contentname)) {
+ const PARCKeyId *publisherKeyId = ccnxPortal_GetKeyId(portal);
+
+ char buffer[128];
+ time_t theTime = time(0);
+ sprintf(buffer, "Hello World. The time is %s", ctime(&theTime));
+
+ PARCBuffer *payload = parcBuffer_CreateFromArray(buffer, 128);
+ parcBuffer_Flip(payload);
+
+ PARCBuffer *b = parcBuffer_Acquire(payload);
+ CCNxContentObject *uob = ccnxContentObject_CreateWithNameAndPayload(contentname, b);
+
+ // missing NULL check, case 1024
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(uob);
+ if (ccnxPortal_Send(portal, message, CCNxTransportStackTimeCCNxStackTimeout_Neverout_Never) == false) {
+ fprintf(stderr, "ccnx_write failed\n");
+ }
+ // ccnxMessage_Release(message);
+ } else if (ccnxName_Equals(interestName, bye)) {
+ break;
+ }
+ } else {
+ ccnxMetaMessage_Display(msg, 0);
+ }
+ ccnxMetaMessage_Release(&msg);
+ }
+ }
+
+ ccnxName_Release(&prefix);
+ ccnxName_Release(&bye);
+ ccnxName_Release(&contentname);
+
+ ccnxPortal_Release(&portal);
+
+ return 0;
+}
+
+int
+ccnx_Portal_Reader(char *keystoreFileName, const char *password, const char *uri)
+{
+ parcSecurity_Init();
+
+ PARCIdentity *identity = getIdentity_FromFile(keystoreFileName, password);
+
+ if (identity != NULL) {
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ reader_writer(factory, uri);
+
+ ccnxPortalFactory_Release(&factory);
+ parcIdentity_Release(&identity);
+ }
+
+ parcSecurity_Fini();
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFileName = argv[1];
+ char *password = argv[2];
+ char *uri = argv[3];
+
+ keystoreFileName = "/tmp/keystore";
+ password = "password";
+ uri = "lci:/Hello";
+
+ // read fileName password lci://my/name lci
+ return ccnx_Portal_Reader(keystoreFileName, password, uri);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c
new file mode 100755
index 00000000..2bb8aadf
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+// Needs to be implemented, case 1037
+int
+main(int argc, char *argv[argc])
+{
+ return 0;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c
new file mode 100755
index 00000000..a9d7a2e6
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c
@@ -0,0 +1,218 @@
+/*
+ * 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 <time.h>
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "ccnxPortalServer_About.h"
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+extern PARCBuffer *makePayload(const CCNxName *interestName, const char *commandString);
+extern int ccnServe(const PARCIdentity *identity, const CCNxName *listenName, const char *commandString);
+extern void usage(void);
+
+PARCBuffer *
+makePayload(const CCNxName *interestName, const char *commandString)
+{
+ char *commandToExecute;
+
+ char *nameAsString = ccnxName_ToString(interestName);
+ int failure = asprintf(&commandToExecute, commandString, nameAsString);
+ assertTrue(failure > -1, "Error asprintf");
+ parcMemory_Deallocate((void **) &nameAsString);
+
+ PARCBufferComposer *accumulator = parcBufferComposer_Create();
+
+ FILE *fp = popen(commandToExecute, "r");
+ if (fp != NULL) {
+ unsigned char buffer[1024];
+
+ while (feof(fp) == 0) {
+ size_t length = fread(buffer, sizeof(char), sizeof(buffer), fp);
+ parcBufferComposer_PutArray(accumulator, buffer, length);
+ }
+ pclose(fp);
+ } else {
+ parcBufferComposer_PutString(accumulator, "Cannot execute: ");
+ parcBufferComposer_PutString(accumulator, commandString);
+ }
+
+ PARCBuffer *payload = parcBufferComposer_ProduceBuffer(accumulator);
+ parcBufferComposer_Release(&accumulator);
+
+ return payload;
+}
+
+int
+ccnServe(const PARCIdentity *identity, const CCNxName *listenName, const char *commandString)
+{
+ parcSecurity_Init();
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ if (ccnxPortal_Listen(portal, listenName, 365 * 86400, CCNxStackTimeout_Never)) {
+ while (true) {
+ CCNxMetaMessage *request = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+
+ if (request == NULL) {
+ break;
+ }
+
+ CCNxInterest *interest = ccnxMetaMessage_GetInterest(request);
+
+ if (interest != NULL) {
+ CCNxName *interestName = ccnxInterest_GetName(interest);
+
+ PARCBuffer *payload = makePayload(interestName, commandString);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(interestName, payload);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never) == false) {
+ fprintf(stderr, "ccnxPortal_Write failed: %d\n", ccnxPortal_GetError(portal));
+ }
+ {
+ char *name = ccnxName_ToString(interestName);
+ time_t theTime = time(0);
+ char *time = ctime(&theTime);
+ printf("%24.24s %s\n", time, name);
+ parcMemory_Deallocate((void **) &name);
+ }
+
+ parcBuffer_Release(&payload);
+ }
+ ccnxMetaMessage_Release(&request);
+ }
+ }
+
+ ccnxPortal_Release(&portal);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+
+ return 0;
+}
+
+void
+usage(void)
+{
+ printf("ccnx-server --identity <file> --password <password> lci:/ccn-name command-to-execute\n");
+ printf("ccnx-server [-h | --help]\n");
+ printf("ccnx-server [-v | --version]\n");
+ printf("\n");
+ printf(" --identity The file name containing a PKCS12 keystore\n");
+ printf(" --password The password to unlock the keystore\n");
+ printf(" lci:/ccn-name The LCI name of the object fetch\n");
+ printf(" program-to-execute The program to run (eg. /bin/date)\n");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFile = NULL;
+ char *keystorePassword = NULL;
+ char *commandString = "/bin/date";
+ char *listenName = "lci:/Server";
+
+ /* options descriptor */
+ static struct option longopts[] = {
+ { "identity", required_argument, NULL, 'f' },
+ { "password", required_argument, NULL, 'p' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "fphvc:", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'f':
+ keystoreFile = optarg;
+ break;
+
+ case 'p':
+ keystorePassword = optarg;
+ break;
+
+ case 'v':
+ printf("%s\n", ccnxPortalServerAbout_Version());
+ return 0;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0] == NULL || keystoreFile == NULL || keystorePassword == NULL) {
+ usage();
+ return -1;
+ }
+ listenName = argv[0];
+ commandString = argv[1];
+ argc += 2;
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFile, keystorePassword);
+
+ if (parcIdentityFile_Exists(identityFile) == false) {
+ printf("Inaccessible keystore file '%s'.\n", keystoreFile);
+ exit(1);
+ }
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ CCNxName *name = ccnxName_CreateFromCString(listenName);
+
+ int result = ccnServe(identity, name, commandString);
+
+ ccnxName_Release(&name);
+
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c
new file mode 100644
index 00000000..ff9465f8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortalClient_About.h"
+
+const char *ccnxPortalClient_What = "@(#)" "CCNx Portal Client " RELEASE_VERSION " 2017-02-22T13:21:28.462492"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalClientAbout_Name(void)
+{
+ return "CCNx Portal Client";
+}
+
+const char *
+ccnxPortalClientAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalClientAbout_About(void)
+{
+ return "CCNx Portal Client "RELEASE_VERSION " 2017-02-22T13:21:28.462492" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_LongNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n";
+}
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h
new file mode 100755
index 00000000..df0c625d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortalClient_About_h
+#define ccnxPortalClient_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortalClient_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalClientAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalClientAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalClientAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_LongNotice(void);
+
+#endif // ccnxPortalClient_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c
new file mode 100644
index 00000000..6596e1bd
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortalServer_About.h"
+
+const char *ccnxPortalServer_What = "@(#)" "CCNx Portal Server " RELEASE_VERSION " 2017-02-22T13:21:39.498237"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalServerAbout_Name(void)
+{
+ return "CCNx Portal Server";
+}
+
+const char *
+ccnxPortalServerAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalServerAbout_About(void)
+{
+ return "CCNx Portal Server "RELEASE_VERSION " 2017-02-22T13:21:39.498237" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_LongNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n";
+}
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h
new file mode 100755
index 00000000..fd95f81f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortalServer_About_h
+#define ccnxPortalServer_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortalServer_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalServerAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalServerAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalServerAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_LongNotice(void);
+
+#endif // ccnxPortalServer_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in b/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in
new file mode 100644
index 00000000..0c02e279
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in
@@ -0,0 +1,3 @@
+//CCNx Portal defines
+
+#define _GNU_SOURCE
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore
new file mode 100644
index 00000000..34eb8191
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore
@@ -0,0 +1,6 @@
+*.aux
+*.out
+*.toc
+*.synctex.gz
+*.texpadtmp
+CCNTransportStackPortal.pdf
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex
new file mode 100644
index 00000000..ffa6f8f1
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex
@@ -0,0 +1,9 @@
+%-
+% ABSTRACT
+%-
+%
+\Abstract{
+The CCN Transport Stack is a software framework that provides facilities for orchestrating the transmission and reception of CCN messages.
+The design of the Transport Stack permits a high degree of configurability enabling different capabilities and behaviors as needed. The CCN Portal API is a programmatic mechanism to create, maintain and use multiple CCN Transport Stacks, each associated with a specific Portal instance.
+Each CCN Portal instance provides a simple programming interface to an associated CCN Transport Stack.
+} \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex
new file mode 100644
index 00000000..9cb0458a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex
@@ -0,0 +1,46 @@
+% A PARC specific refinement of:
+%
+% Stylish Article
+% LaTeX Template
+% Version 2.0 (13/4/14)
+%
+% This template has been downloaded from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Mathias Legrand (legrand.mathias@gmail.com)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%-
+% PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
+%-
+
+\documentclass[fleqn,10pt]{PARCTwoColumn} % Document font size and equations flushed left
+
+%-
+% COLUMNS
+%-
+
+\setlength{\columnsep}{0.55cm} % Distance between the two columns of text
+\setlength{\fboxrule}{0.75pt} % Width of the border around the abstract
+
+%-
+% HYPERLINKS
+%-
+
+\definecolor{color1}{RGB}{0,0,90}
+\definecolor{color2}{RGB}{0,20,20}
+\usepackage{hyperref} % Required for hyperlinks
+\hypersetup{hidelinks,colorlinks,breaklinks=true,urlcolor=color2,citecolor=color1,linkcolor=color1,bookmarksopen=false,pdftitle={Title},pdfauthor={Author}}
+%
+\input{Packages}
+%
+\input{Title}
+%
+\input{Abstract}
+%
+\input{Document}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex
new file mode 100644
index 00000000..b17c33e4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex
@@ -0,0 +1,501 @@
+\begin{document}
+
+\flushbottom % Makes all text pages the same height
+
+\maketitle % Print the title and abstract box
+
+\tableofcontents % Print the contents section
+
+\thispagestyle{empty} % Removes page numbering from the first page
+
+%-
+% ARTICLE CONTENTS
+%-
+
+\section{Overview} % The \section*{} command stops section numbering
+\addcontentsline{toc}{section}{Introduction} % Adds this section to the table of contents
+This document describes the basic client software required to transmit and receive CCN messages
+via CCN Forwarders on a CCN Network. As shown in Figure 1, an application may use the Portal API to manipulate
+the Transport Stack to send and receive messages on a CCN network.
+
+ \begin{figure}[ht]
+\center{\includegraphics[width=205pt]{StackDiagram}}
+\caption{Transport Stack ({\it typ.\/})}
+\end{figure}
+
+
+The Transport Stack is composed of a set of components, each focused on a specific task. Typical stacks include components
+for CCN Flow Control, outbound message signing, inbound message signature verification,
+packet format encoding and decoding, fragmentation and reassembly, and CCN Forwarder communication.
+The extensible architecture supports stacks from the very primitive, providing only mandatory features such as datagram-style message sending and receiving, to the highly sophisticated, providing optional features such as an in-order stream of Content Objects with arbitrary rewind and fast-forward within the stream. Different Transport Stacks may include different features of different implementations of the same
+features.
+
+The Portal API provides a simple interface to the Transport Stack allowing the application to compose, use, and maintain Transport Stacks and to perform message operations through the stack. Each Portal API instance is associated with a specific CCN Transport Stack.
+It is a low-level API providing a simple interface upon which applications and other interfaces are implemented. Examples of higher level services that could leverage the Portal API include the CCN Assembly Framework, the CCN Key-Value Store API, and the CCN Message Queue API.
+
+Together, the Portal API and its associated Transport Stack provide the basic mechanism for sending and receiving CCN messages. These Messages contain Interests, Content Objects, and Control messages.
+Interests and Content Objects are the primary elements of discourse in CCN,
+while Control messages govern the operation of various network elements.
+Taken together, the combination of Portal API associated with a Stack is called a Portal instance.
+The Portal instance is a library of functions that perform operations between the API and the Stack.
+The CCN Portal library creates, maintains, and uses CCN Portal API instances.
+
+\section{Requirements}
+
+\subsection {The Transport Stack}
+The Transport Stack must:
+\begin{itemize}
+\item provide a full interface for the CCN Portal API to access.
+
+\item isolate specific technical concerns into distinct functional components with different experimental and non-experimental implementations.
+
+\item isolate implementation details for encoding and decoding of network packets,
+signing and verification,fragmentation and reassembly, flow and rate control from the application's concern.
+
+\item be able to easily interface with multiple kinds of CCN Forwarder implementations.
+
+\item be easily extensible and a good platform for experimentation.
+\end{itemize}
+
+\subsection {Portal API}
+Each Portal API must:
+
+\begin{itemize}
+\item be able to compose,
+instantiate, associate with, and ultimately use a single
+Transport Stack instantiation using the Transport Framework API.
+
+\item be bound to an identity representing the Portal API instance and its Transport Stack.
+
+\item provide transmission and reception of individual CCN Messages (e.g. Interest, Content Object, and Control messages).
+
+\item provide support for the establishing and abolishing in-bound reception of CCN Messages based upon a CCN Name.
+
+\item provide a facility to set and get attributes related to the state and operation of the Portal instance and its associated Stack. Attributes include:
+\begin{itemize}
+\item an indication of whether dynamically modifiable blocking or non-blocking modes of reception and transmission are used.
+
+\item an indication that a stack will no longer provide or accept inbound or outbound CCN Messages.
+\end{itemize}
+
+\end{itemize}
+\section{Transport Stack}
+The Transport Stack is a component based piece of software following the chain-of-command pattern. It manages two message queues:
+\begin{itemize}
+\item An outbound queue moving messages from the application toward the network.
+\item An inbound queue moving messages from the network toward the application.
+\end{itemize}
+
+As shown in figure 1, The Transport Stack is composed of a set of optional components and two required components: the API Adaptor and the Forwarder Adaptor. Messages are pipelined through the Transport Stack components on their way between the Portal API and the Forwarder. Possible stack components might include elements to handle fragmentation, codecs to translate a programmatic representation of a message into a properly encoded packet, flow control components to manage prefetching, or any other component implemented by a third party. The Transport Stack is designed to be extensible such that an application can utilize as simple or as a sophisticated set of components as it needs.
+
+An application uses the Portal API instance to create, manipulate, and use a Transport Stack.
+The Portal API sends and receives messages through the Transport Stack's API Adaptor.
+
+\subsection{Transport Stack Names}
+The Portal API can reference its own Transport Stack by the name "localstack" in order to set or get properties in the Transport Stack's management information database. This name is valid only within the scope of a single Transport Stack.
+
+A Transport Stack may also have a name assigned to it by its Forwarder Adaptor.
+This name distinguishes one Transport Stack from another within the scope of a single Forwarder.
+
+\subsection{Transport Stack Components}
+A Transport Stack is composed of a set of components through which messages flow in both inbound and outbound directions.
+Each component focuses on a single purpose, thus maintaining a separation of concerns between elements in the stack, and enabling a
+plug-and-play approach to stack composition for different needs.
+
+The following descriptions illustrate typical components in the Transport Stack.
+It is not an exhaustive list, and only the API adaptor and Forwarder Adaptor are required.
+
+\subsubsection{API Adaptor}
+The API adaptor is a required component providing the interface
+between the stack and the application's Portal instance.
+At a minimum, it translates messages between the execution environments of the application and the stack.
+
+\subsubsection{Flow Control}
+The Flow Control component is an optional component
+responsible for managing the flow of outbound and inbound messages to
+ensure in-order delivery, retransmission, sequential fetching and prefetching of messages.
+
+\subsubsection{Codec}
+The Codec component translates a programmatic form of a message into a properly formatted packet suitable for transmission and vice-versa.
+
+The message signature computed over the formatted byte array requires the Codec component to have access to encryption keys for signing and verification.
+This access is provided to the Codec component in any way suitable for the implementation.
+For example, a Codec component implementation might use an identity framework external to the Stack,
+it might participate in a protocol to fetch identity information from the network,
+or it might simply be provided with the identity information from the Portal API via a Control message.
+
+\subsubsection{Fragmentation}
+Fully formatted packets may exceed the size of a maximum transfer unit and as a consequence
+must be fragmented for transmission.
+Similarly, when fragments are received, they must be reassembled into fully formed packets.
+
+\subsubsection{Forwarder Adaptor}
+The Forwarder Adaptor is a required component providing the interface between the Stack and the CCN Forwarder.
+The Forwarder Adaptor is responsible for establishing an association with a CCN Forwarder
+and interacting with the Forwarder to transmit and receive network packets.
+
+For example, a Forwarder implementation may execute on a computer and communicate with all of the Forwarder Adaptors via an IPC mechanism.
+In this case, the Forwarder Adaptor establishes the IPC channel with the Forwarder.
+Similarly, the Forwarder may provide administrative controls out-of-band from the packets it receives. In this case the Forwarder Adaptor is responsible for using those out-of-band controls as necessary.
+
+\subsection{Future}
+The Transport Stack architecture is illustrative but not entirely prescriptive.
+Over time, we expect that well-known, canonical, stack ensembles will emerge
+that are no longer concerned with extensibility or experimentation.
+It would be reasonable to implement such ensembles in as few components as necessary, to promote consistency and ease-of-use.
+Nevertheless, even those omnibus components should be designed with the same requirements for separation of concerns and ease of extensibility or maintenance in mind.
+
+\section{Transport Framework}
+The Transport Framework is responsible for supplying the runtime environment for a Transport Stack.
+It provides an interface for composing and decomposing Transport Stacks and interfaces with the
+necessary system resources (e.g. the operating system, communication interfaces, etc.). While an application
+may start multiple Portal instances with associated Transport Stacks, it will only have one Transport Framework
+to manage all stacks.
+
+\begin{figure}[ht]
+\center{\includegraphics[width=205pt]{TransportStackFramework}}
+\caption{A Transport Framework with multiple, different Transport Stacks.}
+\end{figure}
+
+\section{Portal Instances}
+When a Portal instance is created, it is immediately associated with a Transport Stack
+*{\it under the auspices of a specific identity}.
+
+In this case, the identity is a digital representation of an entity such as an individual, an organization,
+an administrative function, etc.
+The identity should not be confused with a CCN {\it Name} which is a label for something to which messages can be sent, although in some cases
+CCN Named entities may also serve as the identity context of a Portal instance.
+
+\noindent\fbox{\parbox{\textwidth/2 -5\fboxsep-2\fboxrule}{
+{\it *This identity represents the creator of the Stack, which may not necessarily represent the user of the stack.
+For example, an administrative function may create a specific Stack using an administrative identity,
+providing necessary authentication to other services that assist in the creation of the Stack
+then delegate the use of the Stack to an application that does not possess those administrative credentials.}}}
+
+During the course of the Stack's creation and its binding with the Portal instance,
+the Stack acquires a unique CCN LCI name colloquially called "{\tt localstack}". This uniquely identifies the Portal-Stack assembly.
+As a matter of convenience, a specific label from the Labeled Content Information schema is used as shorthand for {\tt localstack}.
+
+A CCN Transport Stack is comprised of multiple components forming a chain-of-command pattern to send and receive CCN messages.
+The formulation of a Stack is prescribed by the Portal instance itself when it is created. For example, Portal instances providing message-by-message-like behavior will create and associate with a Transport Stack providing such behavior;
+Portal instances providing in-order delivery of Content Object messages, being triggered by an initial Interest message,
+will create and associate with a Transport Stack containing components to implement that behavior.
+
+When the life of a CCN Portal instance has ended,
+it is released by its application and resources are deallocated by the operating environment's runtime normally.
+
+Application interactions with the Portal instance consist of invoking methods to send or receive CCN Messages, get or set meta-data regarding the state of the Portal instance.
+
+\subsection{Portal Attributes}
+Transport Stacks are composed of multiple components,
+ each with potentially different attributes that together
+indicate the current state of the stack.
+Each Portal instance maintains a common interface to these attributes.
+
+Some attributes are read-only (for example, a flow control component will signal the state of the flow in a read only attribute),
+while others may be modified only by their specific component (for example, the application specifies blocking or non-blocking modes
+through a read-write attribute).
+
+
+\subsubsection{Queueing Modes}
+
+\begin{enumerate}
+\item {\bf Blocking}
+The client of the Portal instance will block on operations that require a Message to be sent or received if sufficient resources are unavailable.
+\item {\bf Non-blocking}
+The client of the Portal instance will not block on operations that require a Message to be sent or received earn sufficient resources are unavailable.
+\end{enumerate}
+
+
+\subsection{Methods}
+Once a Portal instance is created,
+CCN Messages are sent and received via the appropriate API methods as listed below.
+
+\subsubsection{Send}
+
+The {\tt Send} method enqueues a CCN Message on the outbound queue.
+
+If the queuing mode of the Portal instance is non-blocking and the outbound queue is full,
+this method will fail and signal failure without changing the state of the Portal instance.
+
+If the queuing mode of the Portal instance is blocking and the outbound queue is full,
+this function will block until it is able to successfully enqueue the Message to send.
+
+\subsubsection{Receive}
+
+The {\tt Receive} method dequeues a CCN Message from the inbound queue in the Transport Stack.
+
+If the queuing mode of the Portal instance is non-blocking and the inbound queue is empty,
+this method will fail and signal a temporary failure.
+
+If the queuing mode of the Portal instance is blocking and the inbound queue is empty,
+this function will block until it is able to successfully dequeue a Message to send. {\bf should this be receive?}
+
+\subsubsection{Get Identity}
+Return the Identity associated with the Portal instance.
+
+\subsubsection{Set Identity}
+Set the Identity associated with the Portal instance.
+Setting the Identity does not change the name of the Portal instance. {\bf what is the name?}
+
+\subsubsection{Get Attribute}
+Fetch the value of a named attribute maintained by the Portal instance and its associated Transport Stack.
+
+\subsubsection{Set Attribute}
+Set the value of a named attribute maintained by the Portal instance and its associated Transport Stack.
+The Set is a compare-and-swap wherein a predicate value for the attribute is supplied and if the predicate value
+is equal to the current value of the attribute,
+the attribute value is set to the new value.
+
+\subsubsection{Listen}
+A convenience method that sends the correct Control message to cause CCN Interests with Names starting with a specific prefix to be enqueued in the Transport Stack input queue.
+This operation may require authorization. {\bf why is this a convenience method? Isn't listening and ignoring the main thing to do? who provides authorization}
+
+\subsubsection{Ignore}
+A convenience method that send the correct Control message to cause CCN Interests for Names starting with a specific prefix to not be enqueued in the Transport Stack input queue.
+
+\section{CCN Messages}
+CCN Messages are Interests, Content Objects, and Control messages.
+Each messages contains a CCN Name that directs where the message is sent.
+For example, a CCN Interest message follows the path defined in the Forwarding Information Base (FIB) and deposits an entry in the Pending Interest Table (PIT) of the Forwarder.
+A CCN Content Object messages follows the reverse path specified in the PIT entry and consumes the entry.
+
+\subsection{Interest}
+An Interest is a CCN Message requesting the CCN Content Object message (matching the Name specified in the Interest message) as a response.
+
+\subsection{Content Object}
+
+A Content Object is a CCN Message response to a received CCN Message request.
+
+\subsection{Control}
+Control messages direct the operation of the Portal instance,
+the Transport Stack, and the local Forwarder. They are delivered in the order received by the API or Forwarder Adaptors.
+
+Control Messages are directed to a specific component in a stack by including the LCI name of the component in the message. The Name is a composite of the stack name and the name of a component. For example, a message addressed to the Name {\tt lci:/localstack/codec} would be directed to the {\tt codec} component in the Transport Stack. Every Control message request results in a Control message response. The following section outline a typical set of messages for various Transport Stack components.
+
+{\it
+Notifications as we have them now are just Control messages "up-side-down,"
+or "inbound" rather than outbound.
+A notification is just an unexpected inbound message signalling some state change or information
+(usually after the fact).
+Similarly the control messages are outbound,
+just as unexpected and signal some state change or information
+(usually before the fact).
+So a notification can just be a Control message going the other way.
+
+If we do away with special messages for notifications and special cases for their behavior,
+and reuse the Control Message as both an outbound and inbound message, then the inbound (notification) would require a response.
+But that could be a function of the Portal API library which,
+when it receives an inbound control message always responds with an ACK,
+plus it maintains a representation of the state of the Stack anyway so this is good.
+
+That would have interesting effects:
+I could formulate a control message in my application.
+Send it via Portal down my Transport Stack, through the forwarder to another stack.
+That stack would then receive my control message, possibly act upon it and send a reply.
+Yes I'm skipping over the authorization and authentication part,
+I expect them to be there but I don't expect to always have to describe them.
+
+But at this point, it looks like a CCN Interest again.
+So control messages and notifications just more Interests and Content Objects?
+Or they are Interests and Content Objects with special cased behavior?
+}
+
+
+{\it I make a distinction between Control Messages that affect the stack those that may be transmitted on the network. This is only for clarity at the moment, it may be that they are the same thing, just distinguished by "scope."}
+
+\section{Control Messages for Stack Components}
+\subsection{API Adaptor Control Messages}
+{\tt lci:/localstack/api}
+
+\subsubsection{Pause}
+Cause the API Adaptor and each component subsequently receiving this message
+on the outbound-side of the Stack to not accept any new outbound messages.
+The Forwarder Adaptor must reply to this message and prohibit the enqueing
+of any new inbound message.
+The Forwarder Adaptor's reply indicates to each inbound component
+to not accept any new inbound messages that are not reply messages.
+
+\subsubsection{Resume}
+Cause the API adaptor and each subsequent component to accept new outbound messages,
+The Forwarder Adaptor must reply to this message and enable the enqueing of new inbound messages.
+The Forwarder Adaptor's reply indicates to each inbound component to accept new inbound messages.
+
+\subsubsection{GetAttributes}
+Get the attributes of the API Adaptor Component.
+
+\subsection{Flow Control Control Messages}
+{\tt lci:/localstack/flowcontrol}
+
+The Flow Control component manages the transmission and reception of data comprised of many,
+in-order messages.
+
+A flow is started as the result of the Flow Control component
+receiving an Interest message with the Name containing a valid chunked specification.
+The current position of the flow is set to the value of the chunk
+specified and the limit is set to infinity.
+
+{\it Need a way to name a flow.}
+
+\subsubsection{StartFlow}
+Signal the Flow Control component to start a flow from a specific position to a limit.
+When the flow reaches the limit,
+an inbound message is enqueued signaling that the flow terminated because it reached the limit.
+If the flow terminates before reaching the limit,
+an inbound notification message is enqueued signaling that the flow terminated normally.
+
+\subsubsection{GetPosition}
+Get the current position of the specified flow.
+
+\subsubsection{SetLimit}
+Signal the Flow Control component to immediately set the current limit to the given value.
+The limit can never be set less than the current position.
+
+\subsubsection{GetLimit}
+Get the current limit of the flow.
+
+\paragraph{StopFlow}
+Signal the Flow Control component to immediately stop a flow.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Flow Control Component.
+
+\subsection{Signing Component Control Messages}
+{\tt lci:/localstack/signing}
+
+\subsubsection{SetKey}
+Set the signing key for all subsequent messages.
+
+\subsubsection{UnsetKey}
+Remove the signing key for all subsequent messages.
+Depending upon the implementation behavior of the Signing Component,
+this may cause unsigned messages to be transmitted,
+or the Signing Component may block and signal errors until a new key has been set.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Signing Component.
+
+\subsection{Verification Component Control Messages}
+{\tt lci:/localstack/verification}
+
+\subsubsection{AddKey}
+Add a verification key to the set of keys for valid inbound messages.
+
+\subsubsection{DeleteKey}
+Delete a verification key from the set of keys for valid inbound messages.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Verification Component.
+
+\subsection{Fragmentation Component Control Messages}
+{\tt lci:/localstack/fragmentation}
+
+\subsubsection{GetFragmentSize}
+Get the current Fragment Size used by the Fragmentation Component.
+
+\subsubsection{SetFragmentSize}
+Set the current Fragment Size used by the Fragmentation Component.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Fragmentation Component.
+
+\subsection{Forwarder Adapter Control Messages}
+{\tt lci:/localstack/forwarder}
+
+\subsubsection{CreateRoute}
+Create a FIB entry for the given name to a specified interface.
+The entry must not already exist.
+This operation may require authorization.
+
+\subsubsection{ReadRoute}
+Fetch the FIB entry for the given name.
+If the name does not exist, the reply indicates failure.
+This operation may require authorization.
+
+\subsubsection{UpdateRoute}
+Modify an existing FIB entry for a given name.
+An existing FIB entry must already exist.
+This operation may require authorization.
+
+\subsubsection{DeleteRoute}
+Delete an existing FIB entry for a given name.
+If the name does not exist, the reply indicates failure.
+This operation may require authorization.
+
+\subsubsection{GetRoutes}
+Fetch information about all of the FIB entries in the Forwarder visible by this Portal Stack.
+This operation may require authorization.
+
+\subsubsection{GetInterfaces}
+Fetch information about all interfaces visible by this Portal Stack.
+This operation may require authorization.
+
+\subsubsection{Listen}
+Direct the Forwarder to forward CCN Interests with names starting with a specific prefix to this Portal Stack.
+The Forwarder adaptor enqueues these messages in the Transport Stack input queue.
+This operation may require authorization.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Forwarder Adaptor.
+
+\subsubsection{Ignore}
+Direct the Forwarder to not forward CCN Interests with names starting with a specific prefix to this Portal Stack.
+
+
+%
+%\subsubsection{Request}
+%Request Control messages are either a query or a query/update for state and configuration information for the one or more network elements.
+%
+%For example, a Control message could request the KeyId used by Portal and its associated stack for signing outbound Content Objects.
+%Similarly, a Control message can request the KeyId used by Portal and its associated stack to be changed.
+%
+%\subsubsection{Response}
+%Every Request Control Message produces a Response Control Message which is sent upwards to the Portal to be either read and interpreted by the Portal API implementation, or passed to the client of the Portal API for processing.
+%A Response Control Message indicates either success or failure of the original Request Control Message.
+%
+%\subsubsection{Close}
+%
+%\subsubsection{Add Route}
+%
+%\subsubsection{Add Route To This Stack}
+%
+%%------------------------------------------------
+%
+%\section{Implementation}
+%
+%A CCN Portal instance is created either by the CCN Portal Factory,
+%which is a generator of CCN Portal API instances sharing a common set of attributes held by the factory,
+%or by creating the CCN Portal API instance directly by calling its creation method.
+%
+%\section{Discussion}
+%
+%\subsubsection{Multiple Identities}
+%An example use has been noted where there is a single Portal on which
+%Content Objects to send are to be signed by different keys.
+%A prerequisite for this is for the signing component in the Transport Stack to change the key used to sign Content Objects as they are encoded.
+%
+%Thus, the Portal use would consist of sending a Control Message setting the signing key and sending Content Objects.
+%When a Content Object must be sent signed by a different key, the application uses Portal to send a Control Message setting the new signing key and sending the Content Objects.
+%
+%This has an impact on the semantics and implementation of {\tt GetKeyId} for the Portal instance.
+%For example, does GetKeyId return the KeyId of the current KeyId being used by the Transport Stack's signing component, or does it return the in the most recent Change Key Control message?
+%
+
+%------------------------------------------------
+%\phantomsection
+%\section*{Acknowledgments} % The \section*{} command stops section numbering%
+%
+%\addcontentsline{toc}{section}{Acknowledgments} % Adds this section to the table of contents
+
+
+
+%----------------------------------------------------------------------------------------
+% REFERENCE LIST
+%----------------------------------------------------------------------------------------
+\phantomsection
+%\bibliographystyle{unsrt}
+%\bibliography{sample}
+
+%----------------------------------------------------------------------------------------
+
+\end{document}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls
new file mode 100644
index 00000000..33fe7d29
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls
@@ -0,0 +1,280 @@
+% A PARC specific refinement of:
+%
+% Stylish Article
+% LaTeX Template
+% Version 2.0 (13/4/14)
+%
+% Available from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Mathias Legrand (legrand.mathias@gmail.com)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+% ---------------------------------------------------------------------
+% Conference proceedings and article templates for
+% personal open-archiving activities
+% September 2012
+% ---------------------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{PARCTwoColumn}[25/01/2012, v1.0]
+\RequirePackage{ifthen}
+\RequirePackage{calc}
+\AtEndOfClass{\RequirePackage{microtype}}
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
+\ProcessOptions*
+\LoadClass{article}
+\RequirePackage{ifpdf} % Needed to pick between latex and pdflatex
+
+%----------------------------------------------------------------------
+% FONTS
+%----------------------------------------------------------------------
+
+%\RequirePackage{times} % Loads the Times-Roman Fonts
+\RequirePackage{palatino} % Loads the Palatino Fonts
+%\RequirePackage{mathptmx} % Loads the Times-Roman Math Fonts
+
+%----------------------------------------------------------------------
+% VARIOUS USEFUL PACKAGES
+%----------------------------------------------------------------------
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage{amsmath,amsfonts,amssymb}
+\RequirePackage{graphicx,xcolor}
+\RequirePackage[english]{babel}
+\RequirePackage{booktabs}
+\RequirePackage{multicol}
+\RequirePackage{tabularx}
+
+%----------------------------------------------------------------------
+% MARGINS
+%----------------------------------------------------------------------
+
+\RequirePackage[left=2cm,%
+ right=2cm,%
+ top=2.25cm,%
+ bottom=2.25cm,%
+ headheight=11pt,%
+ letterpaper]{geometry}%
+
+%----------------------------------------------------------------------
+% FIGURES AND TABLES CAPTIONS
+%----------------------------------------------------------------------
+
+\RequirePackage[labelfont={bf,sf,small},%
+ labelsep=period,%
+ justification=raggedright]{caption}
+\setlength{\abovecaptionskip}{0pt}
+\setlength{\belowcaptionskip}{0pt}
+
+%----------------------------------------------------------------------
+% PARC Colors
+%----------------------------------------------------------------------
+
+\definecolor{PARCBlue}{RGB}{32,84,105}
+\definecolor{PARCDarkBlue}{RGB}{0,35,50}
+\definecolor{PARCLightBlue}{RGB}{58,110,143}
+\definecolor{PARCOrange}{RGB}{255,102,0}
+\definecolor{PARCLightGray}{RGB}{213,213,213}
+\definecolor{PARCDarkGray}{RGB}{58,58,58}
+
+\definecolor{AbstractBackgroundColor}{RGB}{58,110,143}
+
+\definecolor{SectionColor}{RGB}{0,0,90} % Color of the article title and sections
+%
+%----------------------------------------------------------------------
+% PAGE HEADER
+%----------------------------------------------------------------------
+%
+\RequirePackage{fancyhdr} % Needed to define custom headers/footers
+\headheight=13.6pt
+\RequirePackage{lastpage} % Number of pages in the document
+\pagestyle{fancy} % Enables the custom headers/footers
+% Headers
+\lhead{}%
+\chead{}%
+\rhead{\small\sffamily\bfseries\@PaperTitle\ --- \thepage/\pageref{LastPage}}
+% Footers
+\lfoot{}%
+\cfoot{}%
+\rfoot{}%
+\renewcommand{\headrulewidth}{0pt}% % No header rule
+\renewcommand{\footrulewidth}{0pt}% % No footer rule
+
+%----------------------------------------------------------------------
+% SECTION/SUBSECTION/PARAGRAPH SET-UP
+%----------------------------------------------------------------------
+
+\RequirePackage[explicit]{titlesec}
+\titleformat{\section}
+ {\color{PARCDarkBlue}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{PARCDarkBlue!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering\arabic{section}. #1}}}
+ []
+\titleformat{name=\section,numberless}
+ {\color{PARCDarkBlue}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{PARCDarkBlue!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering#1}}}
+ []
+\titleformat{\subsection}
+ {\color{PARCDarkBlue}\sffamily\bfseries}
+ {\thesubsection}
+ {0.5em}
+ {#1}
+ []
+\titleformat{\subsubsection}
+ {\sffamily\small\bfseries}
+ {\thesubsubsection}
+ {0.5em}
+ {#1}
+ []
+\titleformat{\paragraph}[runin]
+ {\sffamily\small\bfseries}
+ {}
+ {0em}
+ {#1}
+\titlespacing*{\section}{0pc}{3ex \@plus4pt \@minus3pt}{5pt}
+\titlespacing*{\subsection}{0pc}{2.5ex \@plus3pt \@minus2pt}{0pt}
+\titlespacing*{\subsubsection}{0pc}{2ex \@plus2.5pt \@minus1.5pt}{0pt}
+\titlespacing*{\paragraph}{0pc}{1.5ex \@plus2pt \@minus1pt}{10pt}
+
+%----------------------------------------------------------------------
+% TABLEOFCONTENTS SET-UP
+%----------------------------------------------------------------------
+\newlength{\tocsep}
+\setlength\tocsep{2em} % Sets the indentation of the sections in the table of contents
+\setcounter{tocdepth}{3} % Three levels in the table of contents section: sections, subsections and subsubsections
+
+\usepackage{titletoc}
+\contentsmargin{0cm}
+\titlecontents{section}[\tocsep]
+ {\addvspace{4pt}\small\bfseries\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\hfill\thecontentspage}
+ []
+\titlecontents{subsection}[\tocsep]
+ {\addvspace{2pt}\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\ \titlerule*[.5pc]{.}\ \thecontentspage}
+ []
+\titlecontents*{subsubsection}[\tocsep]
+ {\footnotesize\sffamily}
+ {}
+ {}
+ {}
+ [\ \textbullet\ ]
+
+%----------------------------------------------------------------------
+% MULTIPLE AUTHOR SET
+%----------------------------------------------------------------------
+
+\newcount\@authcnt
+\newcount\@tmpcnt\@tmpcnt\z@
+
+\def\@affiliation{%
+ \ifnum\@tmpcnt<\@authcnt
+ \global\advance\@tmpcnt1
+ \raggedright \csname @auth\romannumeral\the\@tmpcnt\endcsname\hfill\\%
+ \let\next\@affiliation \vskip1pt
+ \else
+ \let\next\relax
+ \fi
+\next}
+
+\newcommand{\affiliation}[1]{%
+ \global\advance\@authcnt1
+ \expandafter\gdef\csname @auth\romannumeral\the\@authcnt\endcsname
+ {#1}}
+
+
+%----------------------------------------------------------------------
+% LIST CONTROL
+%----------------------------------------------------------------------
+
+\RequirePackage{enumitem}
+%\setlist{nolistsep} % Uncomment to remove spacing between items in lists (enumerate, itemize)
+
+%----------------------------------------------------------------------
+% ABSTRACT+AUTHOR FRAME
+%----------------------------------------------------------------------
+
+\newcommand{\PaperTitle}[2]{\def\@PaperTitle{#1}\def\@PaperSubtitle{#2}}
+\newcommand{\Archive}[1]{\def\@Archive{#1}}
+\newcommand{\Authors}[1]{\def\@Authors{#1}}
+\newcommand{\JournalInfo}[1]{\def\@JournalInfo{#1}}
+\newcommand{\Abstract}[1]{\def\@Abstract{#1}}
+\newcommand{\Keywords}[1]{\def\@Keywords{#1}}
+\newcommand{\Masthead}[1]{\def\@Masthead{#1}}
+%
+% ---------------------------------------------------------------------
+%
+\newcommand{\NormalSansBold}[1]{\normalsize\sffamily\bfseries #1}
+\newcommand{\SmallSansBold}[1]{\small\sffamily\bfseries #1}
+\newcommand{\MastHeadText}[1]{\sffamily\bfseries\fontsize{12}{14.4}\selectfont #1}
+%
+\newcommand{\MakePARCMastHead}[1]{
+\setlength{\tabcolsep}{0pt}
+\begin{tabular*}{\textwidth}{l @{\extracolsep{\fill}} p{0.618\textwidth} }
+ \includegraphics[width=140pt]{parc_black_solid}&\vbox{\raggedleft\MastHeadText{#1}\vskip0.5mm}\\
+\end{tabular*}
+}
+%
+\newcommand{\MakeTitle}[2]{%
+{\raggedright\color{SectionColor}\sffamily\bfseries\fontsize{22}{25}\selectfont #1\par}%
+{\raggedright\color{SectionColor}\sffamily\bfseries\fontsize{16}{24}\selectfont #2\par}%
+}
+%
+\newcommand{\MakeAbstract}[2]{%
+\parbox{\textwidth-6\fboxsep-2\fboxrule}{%
+\ifx\@Keywords\@empty%
+\sffamily\textbf{\abstractname}\\#1%
+\else%
+\sffamily\textbf{\abstractname}\\#1\\[4pt]%
+\textbf{\keywordname}\\#2%
+\fi%
+}%
+}%
+%
+\renewcommand{\@maketitle}{%
+\twocolumn[{%
+\thispagestyle{empty}%
+\MakePARCMastHead{\@Masthead}%
+\vskip30pt%
+\MakeTitle{\@PaperTitle}{\@PaperSubtitle}%
+\vskip10pt%
+{\raggedright\color{SectionColor}\sffamily\fontsize{12}{16}\selectfont\@Authors\par}%
+\vskip18pt%
+\fcolorbox{SectionColor}{white}{%
+\parbox{\textwidth-2\fboxsep-2\fboxrule}{\centering%
+\colorbox{AbstractBackgroundColor!10}{%
+\MakeAbstract{\@Abstract}{\@Keywords}
+}%
+\vskip4pt%
+\begingroup%
+\raggedright\sffamily\small%
+\footnotesize\@affiliation\par%
+\endgroup%%
+}%
+}%
+\vskip25pt%
+}]%
+}%
+
+%----------------------------------------------------------------------
+% REFERENCES
+%----------------------------------------------------------------------
+
+% Remove brackets from numbering in List of References
+\renewcommand{\@biblabel}[1]{\bfseries\color{SectionColor}\textsuperscript{[#1]}}
+%\setlength{\bibitemsep}{0cm}
+\let\oldbibliography\thebibliography
+\renewcommand{\thebibliography}[1]{%
+\addcontentsline{toc}{section}{\refname}%
+\oldbibliography{#1}%
+\setlength\itemsep{0pt}}%
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex
new file mode 100644
index 00000000..b09403e8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex
@@ -0,0 +1,46 @@
+%
+% Specify packages that you need in this file.
+% If a package requires configuration, do that here.
+\usepackage{lipsum}
+
+\usepackage{tikz}
+\usetikzlibrary{shadows,arrows}
+% Define the layers to draw the diagram
+\pgfdeclarelayer{background}
+\pgfdeclarelayer{foreground}
+\pgfsetlayers{background,main,foreground}
+
+% Define block styles
+\tikzstyle{materia}=[draw, fill=blue!20, text width=6.0em, text centered,
+ minimum height=1.5em,drop shadow]
+\tikzstyle{component} = [materia, text width=9em, minimum width=10em,
+ minimum height=3em, rounded corners, drop shadow]
+\tikzstyle{texto} = [above, text width=6em, text centered]
+\tikzstyle{linepart} = [draw, thick, color=black!50, -latex', dashed]
+\tikzstyle{line} = [draw, thick, color=black!50, -latex']
+\tikzstyle{ur}=[draw, text centered, minimum height=0.01em]
+
+% Define distances for bordering
+\newcommand{\blockdist}{1.3}
+\newcommand{\edgedist}{1.5}
+
+\newcommand{\component}[3]{node (p#1) [component]%
+ {#2\\{\scriptsize\textit{#3}}}}
+
+% Draw background
+\newcommand{\background}[5]{%
+ \begin{pgfonlayer}{background}
+ % Left-top corner of the background rectangle
+ \path (#1.west |- #2.north)+(-0.5,0.5) node (a1) {};
+ % Right-bottom corner of the background rectangle
+ \path (#3.east |- #4.south)+(+0.5,-0.25) node (a2) {};
+ % Draw the background
+ \path[fill=orange!10,rounded corners, draw=black!50, dashed]
+ (a1) rectangle (a2);
+ \path (a1.east |- a1.south)+(0.8,-0.3) node (u1)[texto]
+ {\scriptsize\textit{#5}};
+ \end{pgfonlayer}}
+
+\newcommand{\transreceptor}[3]{%
+ \path [linepart] (#1.east) -- node [above]
+ {\scriptsize Transreceptor #2} (#3);}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md
new file mode 100644
index 00000000..7d6de0e0
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md
@@ -0,0 +1,16 @@
+# PARC-Two-Column-modular
+An modular template consisting of a single TeX class file (`PARCTwoColumn.cls`), a single TeX source file driving the inclusion of several subsidiary files.
+Consider using this template when the document may need to be included in other layouts,
+keeping the layout separate from content.
+
+A the layout is two columns per page.
+
+To use this template, copy the entire set of files to your own directory that will contain the document.
+
+Modify the following files according to your needs
+
+| :----------- | -------------------: |
+| `Abstract.tex` | The Abstract section of the first page. |
+| `Document.tex` | The entire \begin{document} ... \end{document} segment. |
+| `Packages.tex` | Include required packages and their configurations. |
+| `Title.tex` | The content of the Masthead and Title on the first page. |
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle
new file mode 100644
index 00000000..838445c7
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf
new file mode 100644
index 00000000..7d67e5a4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex
new file mode 100644
index 00000000..c67da1d7
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex
@@ -0,0 +1,15 @@
+%----------------------------------------------------------------------------------------
+% ARTICLE INFORMATION
+%----------------------------------------------------------------------------------------
+\Masthead{Networking and Distributed Systems\\Computing Science Laboratory\\Copyright 2014, PARC Confidential}
+
+\PaperTitle{CCN Transport Stack and Portal API}{} % Article title
+
+\Authors{Glenn Scott\textsuperscript{1}*} % Authors
+\affiliation{\textsuperscript{1}\textit{Computing Science Laboratory, PARC}} % Author affiliation
+\affiliation{*\textbf{Corresponding author}: glenn.scott@parc.com} % Corresponding author
+
+\Keywords{Keyword1 --- Keyword2 --- Keyword3} % Keywords - if you don't want any simply remove all the text between the curly brackets
+\newcommand{\keywordname}{Keywords} % Defines the keywords heading name
+
+\rfoot{PARC Confidential}% \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf
new file mode 100644
index 00000000..2e78bd03
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png
new file mode 100644
index 00000000..6abcf2f4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib
new file mode 100644
index 00000000..fdd186c9
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib
@@ -0,0 +1,8 @@
+@ARTICLE{Figueredo:2009dg,
+ author = {Figueredo, A.~J. and Wolf, P. S.~A.},
+ title = {Assortative pairing and life history strategy - a cross-cultural study.},
+ journal = {Human Nature},
+ volume = {20},
+ pages = {317-330},
+ year = {2009}
+} \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore
new file mode 100644
index 00000000..1d17bd28
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore
@@ -0,0 +1,9 @@
+my_keystore
+test_ccnx_Portal
+test_ccnx_PortalAPI
+test_ccnx_PortalFactory
+test_ccnx_PortalImplementation
+test_ccnx_PortalImplementation_keystore
+test_ccnx_PortalStack
+test_ccnx_PortalRTA
+test_ccnx_PortalAnchor
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt
new file mode 100644
index 00000000..88ce6f1a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnx_Portal
+ test_ccnx_PortalFactory
+ test_ccnx_PortalStack
+ test_ccnx_PortalAPI
+ test_ccnx_PortalRTA
+ test_ccnx_PortalAnchor
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG b/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG
new file mode 100644
index 00000000..b12907ad
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG
@@ -0,0 +1,25 @@
+Tue Nov 17 11:07:47 PST 2015
+test_ccnx_Portal: 2 fixtures
+test_ccnx_Portal/Global: Ran 15 test cases. 100% (15) succeeded
+test_ccnx_Portal/Global/ccnxPortal_Open 1.003460s 0.000000s 0.000000s 58088 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Open_NonBlocking 1.004843s 0.000000s 0.000000s 7633 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Send 1.005196s 0.000000s 0.000000s 9095 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetStatus 1.005718s 0.000000s 0.000000s 8515 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetError 1.001110s 0.000000s 0.000000s 9675 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetFileId 1.004810s 0.000000s 0.000000s 9326 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Listen 1.005183s 0.000000s 0.000000s 11009 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Ignore 1.002009s 0.000000s 0.000000s 12281 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetKeyId 1.004295s 0.000000s 0.000000s 6628 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_IsEOF 1.001509s 0.000000s 0.000000s 8789 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_IsError 1.001177s 0.000000s 0.000000s 9116 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_NeverTimeout 1.004686s 0.000000s 0.000000s 14333 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_ImmediateTimeout 3.005053s 0.000000s 0.000000s 22072 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_ImmediateTimeout_NoData 1.003191s 0.000000s 0.000000s 6700 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_5SecondTimeout 6.005013s 0.000000s 0.000000s 16884 Succeeded
+test_ccnx_Portal/Performance: Ran 3 test cases. 100% (3) succeeded
+test_ccnx_Portal/Performance/ccnxPortalFactory_CreatePortal 4.504010s 0.000000s 0.000000s 4582325 Succeeded
+test_ccnx_Portal/Performance/ccnxPortal_Send 23.504715s 0.000000s 0.000000s 92851121 Succeeded
+test_ccnx_Portal/Performance/ccnxPortal_SendReceive 1.004153s 0.000000s 0.000000s 11961 Succeeded
+Program ended with exit code: 0
+
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c
new file mode 100644
index 00000000..154b8be8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c
@@ -0,0 +1,826 @@
+/*
+ * 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_Portal.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <sys/errno.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/developer/parc_Stopwatch.h>
+
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+//#define USE_APILOOPBACK
+
+#ifdef USE_APILOOPBACK
+# define TEST_STACK ccnxPortalAPI_LoopBack
+#else
+# define TEST_STACK ccnxPortalRTA_LoopBack
+#endif
+
+LONGBOW_TEST_RUNNER(test_ccnx_Portal /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+#define perTestCase
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_Portal)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_Portal)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Open);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Open_NonBlocking);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetStatus);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetError);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Listen);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Ignore);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetKeyId);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_IsEOF);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_IsError);
+
+// LONGBOW_RUN_TEST_CASE(Global, Hello);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout);
+// LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout_Hang);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout_NoData);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_5SecondTimeout);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_NeverTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout_WouldBlock);
+}
+
+static uint32_t InitialMemoryOutstanding = 0;
+
+typedef struct test_data {
+ BentPipeState *bentpipe;
+ CCNxPortalFactory *factory;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+ if (InitialMemoryOutstanding != 0) {
+ printf("Global fixture setup has outstanding allocations %u\n", InitialMemoryOutstanding);
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ }
+
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char bent_pipe_name[1024];
+ static const char bent_pipe_format[] = "/tmp/test_ccnx_Portal%d.sock";
+ sprintf(bent_pipe_name, bent_pipe_format, getpid());
+ unlink(bent_pipe_name);
+ setenv("BENT_PIPE_NAME", bent_pipe_name, 1);
+
+ data->bentpipe = bentpipe_Create(bent_pipe_name);
+ bentpipe_Start(data->bentpipe);
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Portal";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ data->factory = ccnxPortalFactory_Create(identity);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ sleep(2);
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&data->factory);
+
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+
+ parcMemory_Deallocate((void **) &data);
+ unsetenv("BENT_PIPE_NAME");
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %d\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+// return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+char *keyStoreFileName = "/tmp/test_ccnx_Portal.keystore";
+char *keyStorePassWord = "password";
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Open)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ parcObjectTesting_AssertAcquire(portal);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Open_NonBlocking)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+
+ parcObjectTesting_AssertAcquire(portal);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ bool actual = ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Send to be successful.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetStatus)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ const CCNxPortalStatus *status = ccnxPortal_GetStatus(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertNotNull(status, "Expected non-null result from ccnxPortal_GetStatus");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetError)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ const int error = ccnxPortal_GetError(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(error == 0, "Expected 0 result from ccnxPortal_GetError");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetFileId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+ int fileId = ccnxPortal_GetFileId(portal);
+ assertTrue(fileId != -1, "Expected ccnxPortal_GetFileId to not return -1");
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_IsEOF)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ bool actual = ccnxPortal_IsEOF(portal);
+
+ ccnxInterest_Release(&interest);
+ ccnxMetaMessage_Release(&message);
+
+ ccnxPortal_Release(&portal);
+
+ assertFalse(actual, "Expected to not be at EOF");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_IsError)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ bool actual = ccnxPortal_IsError(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertFalse(actual, "Expected not to have an error status");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Listen)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ bool actual = ccnxPortal_Listen(portal, name, 60, CCNxStackTimeout_Never);
+
+ ccnxName_Release(&name);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Listen to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Ignore)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ bool actual = ccnxPortal_Ignore(portal, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Ignore to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetKeyId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ const PARCKeyId *actual = ccnxPortal_GetKeyId(portal);
+ const PARCKeyId *expected = ccnxPortalFactory_GetKeyId(data->factory);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(parcKeyId_Equals(actual, expected), "Expected the PARCKeyId instances to be equal.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_NeverTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ for (int count = 0; count < 10000; count++) {
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate) == false) {
+ break;
+ }
+ count++;
+ }
+
+ assertFalse(ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate),
+ "Expected send to fail due to blocking");
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxInterest_Release(&interest);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout_Hang)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ sleep(2);
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Immediate);
+
+ assertTrue(ccnxInterest_Equals(interest, ccnxMetaMessage_GetInterest(message)), "Expected Interest to be received.");
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxInterest_Release(&interest);
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout_NoData)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ ccnxPortal_Receive(portalIn, CCNxStackTimeout_Immediate);
+ assertTrue(errno == ENOMSG, "Expected errno to be set to ENOMSG, actual %s", strerror(errno));
+
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_5SecondTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ ccnxPortal_Receive(portalIn, CCNxStackTimeout_MicroSeconds(5000000));
+ assertTrue(errno == ENOMSG, "Expected errno to be set to ENOMSG, actual %s", strerror(errno));
+
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, Hello)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portal, interestMessage, CCNxStackTimeout_Never)) {
+ for (int responses = 0; responses == 0; ) {
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ if (message != NULL) {
+ if (ccnxMetaMessage_IsContentObject(message)) {
+ CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(message);
+
+ PARCBuffer *payload = ccnxContentObject_GetPayload(contentObject);
+ if (parcBuffer_HasRemaining(payload) == false) {
+ fprintf(stderr, "**************** Content object has arrived WITH EMPTY CONTENT\n");
+ } else {
+ char *string = parcBuffer_ToString(payload);
+ fprintf(stderr, "**************** Content object has arrived: %s\n", string);
+ parcMemory_Deallocate((void **) &string);
+ }
+ responses++;
+ }
+ ccnxMetaMessage_Release(&message);
+ }
+ }
+ }
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortal_SendReceive);
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortalFactory_CreatePortal);
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortal_Send);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char bent_pipe_name[1024];
+ static const char bent_pipe_format[] = "/tmp/test_ccnx_Portal%d.sock";
+ sprintf(bent_pipe_name, bent_pipe_format, getpid());
+ setenv("BENT_PIPE_NAME", bent_pipe_name, 1);
+
+ data->bentpipe = bentpipe_Create(bent_pipe_name);
+ bentpipe_Start(data->bentpipe);
+
+ longBowTestRunner_SetClipBoardData(testRunner, data->bentpipe);
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Comm";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ data->factory = ccnxPortalFactory_Create(identity);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&data->factory);
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+ parcMemory_Deallocate((void **) &data);
+ unsetenv("BENT_PIPE_NAME");
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %d\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortalFactory_CreatePortal)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ for (int i = 0; i < 1000; i++) {
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ ccnxPortal_Release(&portal);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortal_Send)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ for (int i = 0; i < 100000; i++) {
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+ }
+
+ ccnxPortal_Release(&portal);
+}
+
+typedef struct parc_ewma {
+ bool initialized;
+ int64_t value;
+ double coefficient;
+} PARCEWMA;
+
+PARCEWMA *
+parcEWMA_Create(double coefficient)
+{
+ PARCEWMA *result = parcMemory_AllocateAndClear(sizeof(PARCEWMA));
+ if (result != NULL) {
+ result->initialized = false;
+ result->value = 0;
+ result->coefficient = coefficient;
+ }
+
+ return result;
+}
+
+void
+parcEWMW_Destroy(PARCEWMA **ewma)
+{
+ parcMemory_Deallocate(ewma);
+}
+
+int64_t
+parcEWMA_Update(PARCEWMA *ewma, int64_t value)
+{
+ if (ewma->initialized) {
+ ewma->value = ((value + ewma->coefficient * ewma->value - ewma->value) / ewma->coefficient);
+ } else {
+ ewma->value = value;
+ ewma->initialized = true;
+ }
+ return ewma->value;
+}
+
+int64_t
+parcEWMA_GetValue(const PARCEWMA *ewma)
+{
+ return ewma->value;
+}
+
+static uint64_t
+sendx(CCNxPortal *portalOut, uint32_t index, const CCNxName *name)
+{
+ PARCStopwatch *timer = parcStopwatch_Create();
+
+ parcStopwatch_Start(timer);
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ PARCBuffer *payload = parcBuffer_Allocate(sizeof(uint64_t) + sizeof(uint32_t));
+ parcBuffer_PutUint32(payload, index);
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ uint64_t theTime = tv.tv_sec * 1000000 + tv.tv_usec;
+ parcBuffer_PutUint64(payload, theTime);
+ parcBuffer_Flip(payload);
+
+ ccnxInterest_SetPayload(interest, payload);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never);
+
+ parcBuffer_Release(&payload);
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxInterest_Release(&interest);
+
+ uint64_t result = parcStopwatch_ElapsedTimeNanos(timer);
+ parcStopwatch_Release(&timer);
+ return result;
+}
+
+static void *
+sender(void *data)
+{
+ CCNxPortal *portalOut = data;
+
+ PARCEWMA *ewma = parcEWMA_Create(0.75);
+ CCNxName *name = ccnxName_CreateFormatString("lci:/local/trace");
+
+ for (uint32_t i = 300; i != 0; i--) {
+ uint64_t elapsedTime = sendx(portalOut, i, name);
+ parcEWMA_Update(ewma, elapsedTime);
+ }
+ uint64_t elapsedTime = sendx(portalOut, 0, name);
+ parcEWMA_Update(ewma, elapsedTime);
+
+ printf("sender %9" PRId64 " us/message\n", parcEWMA_GetValue(ewma));
+
+ parcEWMW_Destroy(&ewma);
+ ccnxName_Release(&name);
+ return 0;
+}
+
+static void *
+receiver(void *data)
+{
+ CCNxPortal *portalIn = data;
+
+ uint32_t index;
+ PARCEWMA *ewma = parcEWMA_Create(0.75);
+ PARCEWMA *roundTrip = parcEWMA_Create(0.75);
+
+ PARCStopwatch *timer = parcStopwatch_Create();
+ do {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ uint64_t theTime = tv.tv_sec * 1000000 + tv.tv_usec;
+
+ parcStopwatch_Start(timer);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+
+ PARCBuffer *payload = ccnxInterest_GetPayload(ccnxMetaMessage_GetInterest(message));
+
+ index = parcBuffer_GetUint32(payload);
+
+ parcEWMA_Update(roundTrip, theTime - parcBuffer_GetUint64(payload));
+
+ parcEWMA_Update(ewma, parcStopwatch_ElapsedTimeNanos(timer));
+
+ ccnxMetaMessage_Release(&message);
+ } while (index != 0);
+
+ printf("receiver %9" PRId64 " us/message %9" PRId64 " us\n", parcEWMA_GetValue(ewma), parcEWMA_GetValue(roundTrip));
+
+ parcStopwatch_Release(&timer);
+ parcEWMW_Destroy(&roundTrip);
+ parcEWMW_Destroy(&ewma);
+
+ return 0;
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortal_SendReceive)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portalSend = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalReceive = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ pthread_t thread_receiver1;
+ pthread_t thread_sender;
+ pthread_create(&thread_receiver1, NULL, receiver, portalReceive);
+ pthread_create(&thread_sender, NULL, sender, portalSend);
+
+ pthread_join(thread_receiver1, NULL);
+
+ ccnxPortal_Flush(portalSend, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portalReceive, CCNxStackTimeout_Never);
+ ccnxPortal_Release(&portalSend);
+ ccnxPortal_Release(&portalReceive);
+ sleep(2);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_Portal);
+ int exitStatus = longBowMain(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c
new file mode 100755
index 00000000..736e6982
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c
@@ -0,0 +1,175 @@
+/*
+ * 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_Portal.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/security/parc_IdentityFile.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalAPI /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalAPI)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_PortalAPI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_SendReceive);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_GetFileId);
+}
+
+static size_t InitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Comm";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, factory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %zd\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_CreateRelease)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+ assertNotNull(portal, "Expected a portal");
+
+ ccnxPortal_Release(&portal);
+ assertNull(portal, "Expected a null portal");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_SendReceive)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+
+ // Send Hello
+ CCNxName *name1 = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *sentInterest1 = ccnxInterest_CreateSimple(name1);
+ ccnxName_Release(&name1);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(sentInterest1);
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+
+ // Send Goodbye. We want to make sure these arrive in that order.
+ CCNxName *name2 = ccnxName_CreateFromCString("lci:/Goodbye/World");
+ CCNxInterest *sentInterest2 = ccnxInterest_CreateSimple(name2);
+ ccnxName_Release(&name2);
+
+ message = ccnxMetaMessage_CreateFromInterest(sentInterest2);
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+
+ // Now verify that they arrive in Hello, Goodbye order.
+
+ CCNxMetaMessage *receivedMessage = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+
+ CCNxInterest *receivedInterest1 = ccnxMetaMessage_GetInterest(receivedMessage);
+ assertTrue(ccnxInterest_Equals(sentInterest1, receivedInterest1), "Expected the Hello interest");
+ ccnxMetaMessage_Release(&receivedMessage);
+ ccnxInterest_Release(&sentInterest1);
+
+ receivedMessage = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ CCNxInterest *receivedInterest2 = ccnxMetaMessage_GetInterest(receivedMessage);
+ assertTrue(ccnxInterest_Equals(sentInterest2, receivedInterest2), "Expected the Goodbye interest");
+ ccnxMetaMessage_Release(&receivedMessage);
+ ccnxInterest_Release(&sentInterest2);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_GetFileId)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+
+ int fileId = ccnxPortal_GetFileId(portal);
+
+ assertTrue(fileId != -1, "Expected file-id to not be -1");
+
+ ccnxPortal_Release(&portal);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalAPI);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c
new file mode 100644
index 00000000..b2acbf51
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c
@@ -0,0 +1,286 @@
+/*
+ * 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_PortalAnchor.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_PortalAnchor)
+{
+ // 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(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_PortalAnchor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_PortalAnchor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ assertNotNull(instance, "Expected non-null result from ccnxPortalAnchor_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxPortalAnchor_Acquire, instance);
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+ assertNull(instance, "Expected null result from ccnxPortalAnchor_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Display);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_ToString);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_SerializeDeserialize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Copy)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ CCNxPortalAnchor *copy = ccnxPortalAnchor_Copy(instance);
+ assertTrue(ccnxPortalAnchor_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxPortalAnchor_Release(&copy);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Display)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ ccnxPortalAnchor_Display(instance, 0);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Equals)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *x = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *y = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *z = ccnxPortalAnchor_Create(name, expireTime);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ ccnxPortalAnchor_Release(&x);
+ ccnxPortalAnchor_Release(&y);
+ ccnxPortalAnchor_Release(&z);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_HashCode)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *x = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *y = ccnxPortalAnchor_Create(name, expireTime);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ ccnxPortalAnchor_Release(&x);
+ ccnxPortalAnchor_Release(&y);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_IsValid)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ assertTrue(ccnxPortalAnchor_IsValid(instance), "Expected ccnxPortalAnchor_Create to result in a valid instance.");
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+
+ assertFalse(ccnxPortalAnchor_IsValid(instance), "Expected ccnxPortalAnchor_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_ToJSON)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCJSON *json = ccnxPortalAnchor_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_ToString)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ char *string = ccnxPortalAnchor_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from ccnxPortalAnchor_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_SerializeDeserialize)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_Serialize(instance, composer);
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ CCNxPortalAnchor *copy = ccnxPortalAnchor_Deserialize(buffer);
+
+ assertTrue(ccnxPortalAnchor_Equals(instance, copy), "Expected deserialized form to be equal to the original");
+ ccnxPortalAnchor_Release(&copy);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxPortalAnchor_GetNamePrefix);
+
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxPortalAnchor_GetExpireTime);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxPortalAnchor_GetNamePrefix)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *anchor = ccnxPortalAnchor_Create(name, expireTime);
+
+ CCNxName *actual = ccnxPortalAnchor_GetNamePrefix(anchor);
+
+ assertTrue(ccnxName_Equals(name, actual), "Expected name to be equal.");
+ ccnxPortalAnchor_Release(&anchor);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxPortalAnchor_GetExpireTime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *anchor = ccnxPortalAnchor_Create(name, expireTime);
+
+ time_t actual = ccnxPortalAnchor_GetExpireTime(anchor);
+
+ assertTrue(expireTime == actual, "Expected expire-time to be equal.");
+ ccnxPortalAnchor_Release(&anchor);
+ ccnxName_Release(&name);
+}
+
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_PortalAnchor);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c
new file mode 100644
index 00000000..8c98705f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+#include "../ccnx_PortalFactory.c"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalFactory /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalFactory)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_PortalFactory)
+{
+// LongBowSubProcess *metis = longBowTestRunner_GetClipBoardData(testRunner);
+// longBowSubProcess_Display(0, metis);
+// longBowSubProcess_Destroy(&metis);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_Create);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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(CreateAcquireRelease, ccnxPortalFactory_Create)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_AcquireRelease)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ CCNxPortalFactory *reference = ccnxPortalFactory_Acquire(factory);
+ assertTrue(factory == reference, "Expected Acquire to return its argument.");
+
+ ccnxPortalFactory_Release(&factory);
+ ccnxPortalFactory_Release(&reference);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalFactory_GetIdentity);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalFactory_GetKeyId);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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, ccnxPortalFactory_GetIdentity)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ const PARCIdentity *actual = ccnxPortalFactory_GetIdentity(factory);
+
+ assertTrue(identity == actual, "Expected the result to be the same as provided to the constructor");
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ ccnxPortalFactory_Release(&factory);
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalFactory_GetKeyId)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ const PARCKeyId *actual = ccnxPortalFactory_GetKeyId(factory);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(identity);
+ PARCKeyId *expected = parcSigner_CreateKeyId(signer);
+ parcSigner_Release(&signer);
+
+ assertTrue(parcKeyId_Equals(expected, actual), "KeyIds not equal");
+
+ parcKeyId_Release(&expected);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, ccnxPortalFactory_Create_NULL_Identity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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(Errors, ccnxPortalFactory_Create_NULL_Identity, .event = &LongBowTrapInvalidValue)
+{
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(NULL);
+
+ ccnxPortalFactory_Release(&factory);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalFactory);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c
new file mode 100755
index 00000000..901b1b7e
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c
@@ -0,0 +1,217 @@
+/*
+ * 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 Runner.
+#include "../ccnx_PortalRTA.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnx_PortalRTA)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_PortalRTA)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_PortalRTA)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_Chunked);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_LoopBack);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_Message);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_Chunked)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_LoopBack)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_Message)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _autowrap_destroy__CCNxPortalRTAContext);
+ LONGBOW_RUN_TEST_CASE(Static, _blockingPortal);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalProtocol_RTALoopback);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalProtocol_RTAMetis);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Create);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Destroy);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Release);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_CreatePortal);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_GetAttributes);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Ignore);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_IsConnected);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Listen);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Receive);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Send);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_SetAttributes);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Start);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Stop);
+ LONGBOW_RUN_TEST_CASE(Static, _createTransportConfig);
+ LONGBOW_RUN_TEST_CASE(Static, _nonBlockingPortal);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _autowrap_destroy__CCNxPortalRTAContext)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _blockingPortal)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalProtocol_RTALoopback)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalProtocol_RTAMetis)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_CreatePortal)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_GetAttributes)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_GetFileId)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Ignore)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_IsConnected)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Listen)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Receive)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Send)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_SetAttributes)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Start)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Stop)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _createTransportConfig)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _nonBlockingPortal)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_PortalRTA);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c
new file mode 100755
index 00000000..ebba0dea
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c
@@ -0,0 +1,366 @@
+/*
+ * 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_PortalStack.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_IdentityFile.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalStack)
+{
+ // 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(CreateRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalStack)
+{
+ 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(test_ccnx_PortalStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE(CreateRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateRelease, CreateRelease);
+}
+
+static uint32_t setupFixtureAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateRelease)
+{
+ setupFixtureAllocations = parcMemory_Outstanding();
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_ccnx_PortalImplementation_keystore";
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, factory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateRelease)
+{
+ CCNxPortalFactory *factory = (CCNxPortalFactory *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(setupFixtureAllocations, "%s", longBowTestCase_GetName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_mockStart(void *privateData)
+{
+}
+
+static void
+_mockStop(void *privateData)
+{
+}
+
+static CCNxMetaMessage *
+_mockRead(void *privateData, const uint64_t *microSeconds)
+{
+ CCNxName *name = ccnxName_Create();
+ PARCBuffer *payload = parcBuffer_Allocate(10);
+ CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxName_Release(&name);
+
+ parcBuffer_Release(&payload);
+
+ CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(object);
+ ccnxContentObject_Release(&object);
+ return result;
+}
+
+static bool
+_mockSend(void *privateData, const CCNxMetaMessage *message, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static bool
+_mockListen(void *privateData, const CCNxName *name, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static bool
+_mockIgnore(void *privateData, const CCNxName *name, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static int
+_mockGetFileId(void *privateData)
+{
+ return 2;
+}
+
+static CCNxPortalAttributes *
+_mockGetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_mockSetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ return true;
+}
+
+LONGBOW_TEST_CASE(CreateRelease, CreateRelease)
+{
+ CCNxPortalFactory *factory = (CCNxPortalFactory *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortalAttributes *attributes = NULL;
+ CCNxPortalStack *actual =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _mockStart,
+ _mockStop,
+ _mockRead,
+ _mockSend,
+ _mockListen,
+ _mockIgnore,
+ _mockGetFileId,
+ _mockSetAttributes,
+ _mockGetAttributes,
+ parcMemory_Allocate(10),
+ parcMemory_DeallocateImpl);
+
+ parcObjectTesting_AssertAcquire(actual);
+
+ ccnxPortalStack_Release(&actual);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetAttributes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_SetAttributes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Listen);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Ignore);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Send);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Receive);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Start);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetError);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ setupFixtureAllocations = parcMemory_Outstanding();
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_ccnx_PortalImplementation_keystore";
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ const CCNxPortalAttributes *attributes = &ccnxPortalAttributes_NonBlocking;
+
+ CCNxPortalStack *stack = ccnxPortalStack_Create(factory,
+ attributes,
+ _mockStart,
+ _mockStop,
+ _mockRead,
+ _mockSend,
+ _mockListen,
+ _mockIgnore,
+ _mockGetFileId,
+ _mockSetAttributes,
+ _mockGetAttributes,
+ parcMemory_Allocate(10),
+ parcMemory_DeallocateImpl);
+ ccnxPortalFactory_Release(&factory);
+ longBowTestCase_SetClipBoardData(testCase, stack);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalStack_Release(&stack);
+
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(setupFixtureAllocations, "%s", longBowTestCase_GetName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetError)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+ extern int errno;
+ errno = 0;
+ int actual = ccnxPortalStack_GetErrorCode(stack);
+ assertTrue(actual == 0, "Expected ccnxPortalStack_GetErrorCode to return 0, actual %d", actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Start)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = ccnxPortalStack_Start(stack);
+ assertTrue(actual, "Expected ccnxPortalStack_Start to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Stop)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+ bool actual = ccnxPortalStack_Stop(stack);
+
+ assertTrue(actual, "Expected ccnxPortalStack_Stop to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Receive)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxMetaMessage *result = ccnxPortalStack_Receive(stack, CCNxStackTimeout_Never);
+ assertTrue(result, "Expected ccnxPortalStack_Listen to return true.");
+ ccnxMetaMessage_Release(&result);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Send)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ bool result = ccnxPortalStack_Send(stack, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ assertTrue(result, "Expected ccnxPortalStack_Ignore to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Listen)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ bool result = ccnxPortalStack_Listen(stack, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+ assertTrue(result, "Expected ccnxPortalStack_Listen to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Ignore)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ bool result = ccnxPortalStack_Ignore(stack, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+ assertTrue(result, "Expected ccnxPortalStack_Ignore to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_SetAttributes)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ const CCNxPortalAttributes *attributes = &ccnxPortalAttributes_NonBlocking;
+ bool result = ccnxPortalStack_SetAttributes(stack, attributes);
+ assertTrue(result, "Expected ccnxPortalStack_SetAttributes to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetAttributes)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalStack_GetAttributes(stack);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetFileId)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ int fileId = ccnxPortalStack_GetFileId(stack);
+ assertFalse(fileId == -1, "Expected ccnxPortalStack_GetFileId to not return -1.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetKeyId)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCKeyId *keyId = ccnxPortalStack_GetKeyId(stack);
+ assertNotNull(keyId, "Expected non-NULL result from ccnxPortalStack_GetKeyId");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}