summaryrefslogtreecommitdiffstats
path: root/libtransport/src/hicn/transport/core
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/hicn/transport/core')
-rwxr-xr-xlibtransport/src/hicn/transport/core/CMakeLists.txt87
-rwxr-xr-xlibtransport/src/hicn/transport/core/connector.cc44
-rwxr-xr-xlibtransport/src/hicn/transport/core/connector.h89
-rwxr-xr-xlibtransport/src/hicn/transport/core/content_object.cc170
-rwxr-xr-xlibtransport/src/hicn/transport/core/content_object.h69
-rwxr-xr-xlibtransport/src/hicn/transport/core/facade.h53
-rwxr-xr-xlibtransport/src/hicn/transport/core/forwarder_interface.h136
-rwxr-xr-xlibtransport/src/hicn/transport/core/hicn_binary_api.c228
-rwxr-xr-xlibtransport/src/hicn/transport/core/hicn_binary_api.h103
-rwxr-xr-xlibtransport/src/hicn/transport/core/hicn_forwarder_interface.cc84
-rwxr-xr-xlibtransport/src/hicn/transport/core/hicn_forwarder_interface.h67
-rwxr-xr-xlibtransport/src/hicn/transport/core/hicn_memif_api.c0
-rwxr-xr-xlibtransport/src/hicn/transport/core/interest.cc149
-rwxr-xr-xlibtransport/src/hicn/transport/core/interest.h66
-rwxr-xr-xlibtransport/src/hicn/transport/core/key_locator.cc42
-rwxr-xr-xlibtransport/src/hicn/transport/core/key_locator.h48
-rwxr-xr-xlibtransport/src/hicn/transport/core/key_locator_type.h28
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest.cc33
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest.h164
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format.h196
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_fixed.cc221
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_fixed.h168
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc244
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h162
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc298
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h152
-rwxr-xr-xlibtransport/src/hicn/transport/core/manifest_inline.h116
-rwxr-xr-xlibtransport/src/hicn/transport/core/memif_binary_api.c218
-rwxr-xr-xlibtransport/src/hicn/transport/core/memif_binary_api.h61
-rwxr-xr-xlibtransport/src/hicn/transport/core/memif_connector.cc493
-rwxr-xr-xlibtransport/src/hicn/transport/core/memif_connector.h162
-rwxr-xr-xlibtransport/src/hicn/transport/core/name.cc236
-rwxr-xr-xlibtransport/src/hicn/transport/core/name.h133
-rwxr-xr-xlibtransport/src/hicn/transport/core/packet.cc614
-rwxr-xr-xlibtransport/src/hicn/transport/core/packet.h195
-rwxr-xr-xlibtransport/src/hicn/transport/core/payload_type.h29
-rwxr-xr-xlibtransport/src/hicn/transport/core/pending_interest.cc49
-rwxr-xr-xlibtransport/src/hicn/transport/core/pending_interest.h81
-rwxr-xr-xlibtransport/src/hicn/transport/core/portal.h343
-rwxr-xr-xlibtransport/src/hicn/transport/core/prefix.cc211
-rwxr-xr-xlibtransport/src/hicn/transport/core/prefix.h68
-rwxr-xr-xlibtransport/src/hicn/transport/core/raw_socket_connector.cc214
-rwxr-xr-xlibtransport/src/hicn/transport/core/raw_socket_connector.h85
-rwxr-xr-xlibtransport/src/hicn/transport/core/raw_socket_interface.cc57
-rwxr-xr-xlibtransport/src/hicn/transport/core/raw_socket_interface.h51
-rwxr-xr-xlibtransport/src/hicn/transport/core/socket_connector.cc237
-rwxr-xr-xlibtransport/src/hicn/transport/core/socket_connector.h89
-rwxr-xr-xlibtransport/src/hicn/transport/core/test/CMakeLists.txt10
-rwxr-xr-xlibtransport/src/hicn/transport/core/test/test_core_manifest.cc296
-rwxr-xr-xlibtransport/src/hicn/transport/core/vpp_binary_api.c221
-rwxr-xr-xlibtransport/src/hicn/transport/core/vpp_binary_api.h64
-rwxr-xr-xlibtransport/src/hicn/transport/core/vpp_binary_api_internal.h61
-rwxr-xr-xlibtransport/src/hicn/transport/core/vpp_forwarder_interface.cc184
-rwxr-xr-xlibtransport/src/hicn/transport/core/vpp_forwarder_interface.h68
54 files changed, 7747 insertions, 0 deletions
diff --git a/libtransport/src/hicn/transport/core/CMakeLists.txt b/libtransport/src/hicn/transport/core/CMakeLists.txt
new file mode 100755
index 000000000..c8dea8328
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/CMakeLists.txt
@@ -0,0 +1,87 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/facade.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interest.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/key_locator_type.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/name.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/portal.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_interface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_object.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/interest.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/name.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/prefix.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/connector.cc
+)
+
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ if (BUILD_WITH_VPP OR BUILD_VPP_PLUGIN)
+ list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.h
+ )
+
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.c
+ )
+ endif()
+
+ list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.h
+ )
+
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.cc
+ )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/connector.cc b/libtransport/src/hicn/transport/core/connector.cc
new file mode 100755
index 000000000..ff567d78a
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/connector.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/connector.h>
+
+namespace transport {
+
+namespace core {
+
+std::once_flag Connector::init_flag_;
+
+Connector::Connector() : packet_pool_() { init(); }
+
+void Connector::init() { increasePoolSize(); }
+
+void Connector::increasePoolSize(std::size_t size) {
+ // Allocate space for receiving packets
+ const auto capacity = packet_size * size;
+ uint8_t *buffer = static_cast<uint8_t *>(malloc(capacity));
+ std::unique_ptr<utils::MemBuf> buffer0 =
+ utils::MemBuf::takeOwnership(buffer, capacity, 0, nullptr, nullptr, true);
+
+ for (std::size_t i = 1; i < size; i++) {
+ auto b = buffer0->cloneOne();
+ b->advance(i * packet_size);
+ packet_pool_.add(b.release());
+ }
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/connector.h b/libtransport/src/hicn/transport/core/connector.h
new file mode 100755
index 000000000..14201879c
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/connector.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/ring_buffer.h>
+
+#include <deque>
+#include <functional>
+
+namespace transport {
+
+namespace core {
+
+enum class ConnectorType : uint8_t {
+ SOCKET_CONNECTOR,
+ RAW_SOCKET_CONNECTOR,
+ VPP_CONNECTOR,
+};
+
+static constexpr std::size_t packet_size = 2000;
+static constexpr std::size_t queue_size = 4096;
+static constexpr std::size_t packet_pool_size = 4096;
+
+using PacketRing = utils::CircularFifo<Packet::MemBufPtr, queue_size>;
+using PacketQueue = std::deque<Packet::MemBufPtr>;
+using PacketReceivedCallback = std::function<void(Packet::MemBufPtr &&)>;
+using OnReconnect = std::function<void()>;
+using PacketSentCallback = std::function<void()>;
+
+class Connector {
+ public:
+ Connector();
+
+ virtual ~Connector() = default;
+
+ virtual void send(const Packet::MemBufPtr &packet) = 0;
+
+ virtual void send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent = 0) = 0;
+
+ virtual void close() = 0;
+
+ virtual void enableBurst() = 0;
+
+ virtual void state() = 0;
+
+ protected:
+ void increasePoolSize(std::size_t size = packet_pool_size);
+
+ TRANSPORT_ALWAYS_INLINE utils::ObjectPool<utils::MemBuf>::Ptr getPacket() {
+ auto result = packet_pool_.get();
+
+ while (TRANSPORT_EXPECT_FALSE(!result.first)) {
+ // Add packets to the pool
+ increasePoolSize();
+ result = packet_pool_.get();
+ }
+
+ result.second->clear();
+ return std::move(result.second);
+ }
+
+ private:
+ void init();
+
+ protected:
+ static std::once_flag init_flag_;
+ utils::ObjectPool<utils::MemBuf> packet_pool_;
+ PacketQueue output_buffer_;
+};
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/content_object.cc b/libtransport/src/hicn/transport/core/content_object.cc
new file mode 100755
index 000000000..dc2056582
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/content_object.cc
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/content_object.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+}
+
+#include <cstring>
+#include <memory>
+
+namespace transport {
+
+namespace core {
+
+ContentObject::ContentObject(const Name &name, Packet::Format format)
+ : Packet(format) {
+ if (TRANSPORT_EXPECT_FALSE(
+ hicn_data_set_name(format, (hicn_header_t *)packet_start_,
+ name.getStructReference()) < 0)) {
+ throw errors::RuntimeException("Error filling the packet name.");
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(
+ hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0)) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+ContentObject::ContentObject(hicn_format_t format)
+ : ContentObject(Packet::base_name, format) {}
+
+ContentObject::ContentObject(const Name &name, hicn_format_t format,
+ const uint8_t *payload, std::size_t size)
+ : ContentObject(name, format) {
+ appendPayload(payload, size);
+}
+
+ContentObject::ContentObject(const uint8_t *buffer, std::size_t size)
+ : Packet(buffer, size) {
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::RuntimeException("Error getting name from content object.");
+ }
+}
+
+ContentObject::ContentObject(MemBufPtr &&buffer) : Packet(std::move(buffer)) {
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::RuntimeException("Error getting name from content object.");
+ }
+}
+
+ContentObject::ContentObject(ContentObject &&other) : Packet(std::move(other)) {
+ name_ = std::move(other.name_);
+
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+ContentObject::~ContentObject() {}
+
+const Name &ContentObject::getName() const {
+ if (!name_) {
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ (hicn_name_t *)name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ }
+
+ return name_;
+}
+
+ContentObject &ContentObject::setName(const Name &name) {
+ if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_,
+ name.getStructReference()) < 0) {
+ throw errors::RuntimeException("Error setting content object name.");
+ }
+
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
+ return *this;
+}
+
+void ContentObject::setName(Name &&name) {
+ if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_,
+ name.getStructReference()) < 0) {
+ throw errors::RuntimeException(
+ "Error getting the payload length from content object.");
+ }
+
+ if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+uint32_t ContentObject::getPathLabel() const {
+ uint32_t path_label;
+ if (hicn_data_get_path_label((hicn_header_t *)packet_start_, &path_label) <
+ 0) {
+ throw errors::RuntimeException(
+ "Error retrieving the path label from content object");
+ }
+
+ return path_label;
+}
+
+ContentObject &ContentObject::setPathLabel(uint32_t path_label) {
+ if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) <
+ 0) {
+ throw errors::RuntimeException(
+ "Error setting the path label from content object");
+ }
+
+ return *this;
+}
+
+void ContentObject::setLocator(const ip_address_t &ip_address) {
+ if (hicn_data_set_locator(format_, (hicn_header_t *)packet_start_,
+ &ip_address) < 0) {
+ throw errors::RuntimeException("Error setting content object locator");
+ }
+
+ return;
+}
+
+ip_address_t ContentObject::getLocator() const {
+ ip_address_t ip;
+
+ if (hicn_data_get_locator(format_, (hicn_header_t *)packet_start_, &ip) < 0) {
+ throw errors::RuntimeException("Error getting content object locator.");
+ }
+
+ return ip;
+}
+
+void ContentObject::resetForHash() {
+ if (hicn_data_reset_for_hash(
+ format_, reinterpret_cast<hicn_header_t *>(packet_start_)) < 0) {
+ throw errors::RuntimeException(
+ "Error resetting content object fields for hash computation.");
+ }
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/content_object.h b/libtransport/src/hicn/transport/core/content_object.h
new file mode 100755
index 000000000..c85259f20
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/content_object.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/packet.h>
+
+namespace transport {
+
+namespace core {
+
+// This class is used just to transfer buffer pointers
+// without making a copy, as std::vector<> would do
+
+class ContentObject : public Packet {
+ public:
+ using Ptr = utils::ObjectPool<ContentObject>::Ptr;
+ using HICNContentObject = hicn_header_t;
+
+ ContentObject(Packet::Format format = HF_INET6_TCP);
+
+ ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP);
+
+ ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload,
+ std::size_t payload_size);
+
+ ContentObject(const uint8_t *buffer, std::size_t size);
+ ContentObject(MemBufPtr &&buffer);
+
+ ContentObject(const ContentObject &content_object) = delete;
+
+ ContentObject(ContentObject &&content_object);
+
+ ~ContentObject() override;
+
+ const Name &getName() const;
+
+ ContentObject &setName(const Name &name);
+
+ void setName(Name &&name);
+
+ uint32_t getPathLabel() const;
+
+ ContentObject &setPathLabel(uint32_t path_label);
+
+ void setLocator(const ip_address_t &ip_address) override;
+
+ ip_address_t getLocator() const override;
+
+ private:
+ void resetForHash() override;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/facade.h b/libtransport/src/hicn/transport/core/facade.h
new file mode 100755
index 000000000..c28c84671
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/facade.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/hicn_forwarder_interface.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/portal.h>
+
+#ifdef __linux__
+#ifndef __ANDROID__
+#include <hicn/transport/core/raw_socket_interface.h>
+#ifdef __vpp__
+#include <hicn/transport/core/vpp_forwarder_interface.h>
+#endif
+#endif
+#endif
+
+namespace transport {
+
+namespace core {
+
+using HicnForwarderPortal = Portal<HicnForwarderInterface>;
+
+#ifdef __linux__
+#ifndef __ANDROID_API__
+using RawSocketPortal = Portal<RawSocketInterface>;
+#endif
+#ifdef __vpp__
+using VPPForwarderPortal = Portal<VPPForwarderInterface>;
+#endif
+#endif
+
+using ContentObjectManifest = core::ManifestInline<ContentObject, Fixed>;
+using InterestManifest = core::ManifestInline<Interest, Fixed>;
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h
new file mode 100755
index 000000000..e7b6fb1a6
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/forwarder_interface.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/portability/portability.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+typedef struct {
+ uint64_t rx_packets;
+ uint64_t tx_packets;
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+ uint64_t rx_errors;
+ uint64_t tx_errors;
+} Counters;
+
+template <typename Implementation, typename ConnectorType>
+class ForwarderInterface {
+ static_assert(std::is_base_of<Connector, ConnectorType>::value,
+ "T must inherit from connector!");
+
+ static constexpr uint32_t standard_cs_reserved = 5000;
+
+ protected:
+ ForwarderInterface(ConnectorType &c)
+ : connector_(c),
+ inet_address_({}),
+ inet6_address_({}),
+ mtu_(1500),
+ output_interface_(""),
+ content_store_reserved_(standard_cs_reserved) {
+ inet_address_.family = AF_INET;
+ inet6_address_.family = AF_INET6;
+ }
+
+ public:
+ static constexpr uint8_t ack_code = 102;
+
+ virtual ~ForwarderInterface() {}
+
+ TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) {
+ static_cast<Implementation &>(*this).connect(is_consumer);
+ }
+
+ TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) {
+ static_cast<Implementation &>(*this).registerRoute();
+ }
+
+ TRANSPORT_ALWAYS_INLINE std::uint32_t getMtu() {
+ return static_cast<Implementation &>(*this).getMtu();
+ }
+
+ template <
+ typename R,
+ typename = std::enable_if_t<
+ std::is_base_of<Packet, typename std::remove_reference_t<R>>::value,
+ R>>
+ TRANSPORT_ALWAYS_INLINE void send(R &&packet) {
+ counters_.tx_packets++;
+ counters_.tx_bytes += packet.payloadSize() + packet.headerSize();
+
+ if (_is_ipv4(packet.getFormat())) {
+ packet.setLocator(inet_address_);
+ } else {
+ packet.setLocator(inet6_address_);
+ }
+
+ packet.setChecksum();
+ connector_.send(packet.data());
+ }
+
+ template <typename Handler>
+ TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len,
+ Handler &&packet_sent) {
+ // ASIO_COMPLETION_HANDLER_CHECK(Handler, packet_sent) type_check;
+ counters_.tx_packets++;
+ counters_.tx_bytes += len;
+
+ // Perfect forwarding
+ connector_.send(packet, len, std::forward<Handler>(packet_sent));
+ }
+
+ TRANSPORT_ALWAYS_INLINE void shutdown() { connector_.close(); }
+
+ TRANSPORT_ALWAYS_INLINE Connector &getConnector() { return connector_; }
+
+ TRANSPORT_ALWAYS_INLINE void setContentStoreSize(uint32_t cs_size) {
+ content_store_reserved_ = cs_size;
+ }
+
+ TRANSPORT_ALWAYS_INLINE uint32_t getContentStoreSize() const {
+ return content_store_reserved_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void setOutputInterface(
+ const std::string &interface) {
+ output_interface_ = interface;
+ }
+
+ TRANSPORT_ALWAYS_INLINE std::string &getOutputInterface() {
+ return output_interface_;
+ }
+
+ protected:
+ ConnectorType &connector_;
+ ip_address_t inet_address_;
+ ip_address_t inet6_address_;
+ uint16_t mtu_;
+ std::string output_interface_;
+ uint32_t content_store_reserved_;
+ Counters counters_;
+};
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.c b/libtransport/src/hicn/transport/core/hicn_binary_api.c
new file mode 100755
index 000000000..c49cb5c88
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/hicn_binary_api.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vlib/vlib.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+
+#include <vnet/ip/format.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+
+#include <vpp_plugins/hicn/error.h>
+#include <vpp_plugins/hicn/hicn_api.h>
+
+// uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <hicn/hicn_msg_enum.h>
+
+#define vl_endianfun /* define message structures */
+#define vl_print(handle, ...)
+#define vl_printfun
+#define vl_api_version(n, v) static u32 api_version = (v);
+#define vl_msg_name_crc_list
+#include <hicn/hicn_all_api_h.h>
+#undef vl_msg_name_crc_list
+#undef vl_api_version
+#undef vl_printfun
+#undef vl_endianfun
+
+/////////////////////////////////////////////////////
+const char *HICN_ERROR_STRING[] = {
+#define _(a, b, c) c,
+ foreach_hicn_error
+#undef _
+};
+/////////////////////////////////////////////////////
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+#define CONTEXT_SAVE(pointer, mp) \
+ do { \
+ global_pointers_map[global_pointers_map_index] = pointer; \
+ mp->context = global_pointers_map_index++; \
+ global_pointers_map_index %= POINTER_MAP_SIZE; \
+ } while (0);
+
+#define CONTEXT_GET(mp, pointer) \
+ do { \
+ pointer = global_pointers_map[mp->context]; \
+ } while (0);
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_hicn_api_reply_msg \
+ _(HICN_API_REGISTER_PROD_APP_REPLY, hicn_api_register_prod_app_reply) \
+ _(HICN_API_REGISTER_CONS_APP_REPLY, hicn_api_register_cons_app_reply) \
+ _(HICN_API_ROUTE_NHOPS_ADD_REPLY, hicn_api_route_nhops_add_reply)
+
+int hicn_binary_api_register_prod_app(
+ vpp_plugin_binary_api_t *api, hicn_producer_input_params *input_params,
+ hicn_producer_output_params *output_params) {
+ vl_api_hicn_api_register_prod_app_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+ api->vpp_api->user_param = output_params;
+
+ /* Construct the API message */
+ M(HICN_API_REGISTER_PROD_APP, mp);
+
+ CONTEXT_SAVE(api, mp)
+
+ mp->len = (u8)input_params->prefix.prefix_length;
+ mp->swif = clib_host_to_net_u32(input_params->swif);
+ mp->cs_reserved = clib_host_to_net_u32(input_params->cs_reserved);
+
+ mp->prefix[0] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[0]);
+ mp->prefix[1] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[1]);
+
+ TRANSPORT_LOGI("Prefix length: %u", mp->len);
+ TRANSPORT_LOGI("Memif ID: %u", mp->swif);
+
+ return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_register_prod_app_reply_t_handler(
+ vl_api_hicn_api_register_prod_app_reply_t *mp) {
+ vpp_plugin_binary_api_t *binary_api;
+ CONTEXT_GET(mp, binary_api);
+ hicn_producer_output_params *params = binary_api->vpp_api->user_param;
+
+ binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+ params->cs_reserved = mp->cs_reserved;
+ params->prod_addr.ip6.as_u64[0] = mp->prod_addr[0];
+ params->prod_addr.ip6.as_u64[1] = mp->prod_addr[1];
+ params->face_id = clib_net_to_host_u32(mp->faceid);
+
+ TRANSPORT_LOGI("ret :%s", get_error_string(binary_api->vpp_api->ret_val));
+
+ vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+int hicn_binary_api_register_cons_app(
+ vpp_plugin_binary_api_t *api, hicn_consumer_input_params *input_params,
+ hicn_consumer_output_params *output_params) {
+ vl_api_hicn_api_register_cons_app_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+
+ hm->vpp_api->user_param = output_params;
+
+ /* Construct the API message */
+ M(HICN_API_REGISTER_CONS_APP, mp);
+
+ mp->swif = clib_host_to_net_u32(input_params->swif);
+
+ CONTEXT_SAVE(api, mp)
+
+ TRANSPORT_LOGI("Message created");
+
+ return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_register_cons_app_reply_t_handler(
+ vl_api_hicn_api_register_cons_app_reply_t *mp) {
+ vpp_plugin_binary_api_t *binary_api;
+ CONTEXT_GET(mp, binary_api);
+ hicn_consumer_output_params *params = binary_api->vpp_api->user_param;
+
+ binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+
+ params->src4.ip4.as_u32 = clib_net_to_host_u32(mp->src_addr4);
+ params->src6.ip6.as_u64[0] = clib_net_to_host_u64(mp->src_addr6[0]);
+ params->src6.ip6.as_u64[1] = clib_net_to_host_u64(mp->src_addr6[1]);
+ params->face_id = clib_host_to_net_u32(mp->faceid);
+
+ vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+int hicn_binary_api_register_route(
+ vpp_plugin_binary_api_t *api,
+ hicn_producer_set_route_params *input_params) {
+ vl_api_hicn_api_route_nhops_add_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+
+ /* Construct the API message */
+ M(HICN_API_ROUTE_NHOPS_ADD, mp);
+
+ CONTEXT_SAVE(api, mp)
+
+ mp->prefix[0] = input_params->prefix.ip6.as_u64[0];
+ mp->prefix[1] = input_params->prefix.ip6.as_u64[1];
+ mp->len = input_params->prefix.prefix_length;
+ mp->face_ids[0] = input_params->face_id;
+ mp->n_faces = 1;
+
+ return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_route_nhops_add_reply_t_handler(
+ vl_api_hicn_api_route_nhops_add_reply_t *mp) {
+ vpp_plugin_binary_api_t *binary_api;
+ CONTEXT_GET(mp, binary_api);
+
+ binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+
+ vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static int hicn_binary_api_setup_handlers(vpp_plugin_binary_api_t *binary_api) {
+ vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api;
+#define _(N, n) \
+ vl_msg_api_set_handlers(VL_API_##N + sm->msg_id_base, #n, \
+ vl_api_##n##_t_handler, vl_noop_handler, \
+ vl_api_##n##_t_endian, vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_hicn_api_reply_msg;
+#undef _
+ return 0;
+}
+
+char *hicn_binary_api_get_error_string(int ret_val) {
+ return get_error_string(ret_val);
+}
+
+vpp_plugin_binary_api_t *hicn_binary_api_init(vpp_binary_api_t *api) {
+ vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t));
+ u8 *name = format(0, "hicn_%08x%c", api_version, 0);
+ ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name);
+ ret->vpp_api = api;
+ ret->my_client_index = api->my_client_index;
+ hicn_binary_api_setup_handlers(ret);
+ return ret;
+}
+
+#endif // __vpp__
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.h b/libtransport/src/hicn/transport/core/hicn_binary_api.h
new file mode 100755
index 000000000..752844153
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/hicn_binary_api.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/vpp_binary_api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdint.h"
+
+typedef union {
+ uint8_t data[4];
+ uint32_t data_u32;
+ /* Aliases. */
+ uint8_t as_u8[4];
+ uint16_t as_u16[2];
+ uint32_t as_u32;
+} ip4_address;
+
+typedef union {
+ uint8_t as_u8[16];
+ uint16_t as_u16[8];
+ uint32_t as_u32[4];
+ uint64_t as_u64[2];
+} ip6_address;
+
+typedef enum { IP_TYPE_ANY, IP_TYPE_IP4, IP_TYPE_IP6 } ip46_type;
+
+typedef struct {
+ ip46_type type;
+ uint8_t prefix_length;
+ union {
+ ip4_address ip4;
+ ip6_address ip6;
+ };
+} ip46_address;
+
+typedef struct {
+ ip46_address prefix;
+ uint32_t swif;
+ uint32_t cs_reserved;
+} hicn_producer_input_params;
+
+typedef struct {
+ uint32_t swif;
+} hicn_consumer_input_params;
+
+typedef struct {
+ uint32_t cs_reserved;
+ ip46_address prod_addr;
+ uint32_t face_id;
+} hicn_producer_output_params;
+
+typedef struct {
+ ip46_address src4;
+ ip46_address src6;
+ uint32_t face_id;
+} hicn_consumer_output_params;
+
+typedef struct {
+ ip46_address prefix;
+ uint32_t face_id;
+} hicn_producer_set_route_params;
+
+vpp_plugin_binary_api_t* hicn_binary_api_init(vpp_binary_api_t* api);
+
+int hicn_binary_api_register_prod_app(
+ vpp_plugin_binary_api_t* api, hicn_producer_input_params* input_params,
+ hicn_producer_output_params* output_params);
+
+int hicn_binary_api_register_cons_app(
+ vpp_plugin_binary_api_t* api, hicn_consumer_input_params* input_params,
+ hicn_consumer_output_params* output_params);
+
+int hicn_binary_api_register_route(
+ vpp_plugin_binary_api_t* api, hicn_producer_set_route_params* input_params);
+
+char* hicn_binary_api_get_error_string(int ret_val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc
new file mode 100755
index 000000000..03a294957
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/hicn_forwarder_interface.h>
+
+#define ADDR_INET 1
+#define ADDR_INET6 2
+#define ADD_ROUTE 3
+#define REQUEST_LIGHT 100
+
+union AddressLight {
+ uint32_t ipv4;
+ struct in6_addr ipv6;
+};
+
+typedef struct {
+ uint8_t message_type;
+ uint8_t command_id;
+ uint16_t length;
+ uint32_t seq_num;
+ char symbolic_or_connid[16];
+ union AddressLight address;
+ uint16_t cost;
+ uint8_t address_type;
+ uint8_t len;
+} RouteToSelfCommand;
+
+namespace transport {
+
+namespace core {
+
+HicnForwarderInterface::HicnForwarderInterface(SocketConnector &connector)
+ : ForwarderInterface<HicnForwarderInterface, SocketConnector>(connector) {}
+
+HicnForwarderInterface::~HicnForwarderInterface() {}
+
+void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); }
+
+void HicnForwarderInterface::registerRoute(Prefix &prefix) {
+ auto addr = prefix.toSockaddr();
+ const char *identifier = {"SELF_ROUTE"};
+
+ // allocate command payload
+ RouteToSelfCommand *route_to_self = new RouteToSelfCommand();
+
+ // check and set IP address
+ if (addr->sa_family == AF_INET) {
+ route_to_self->address_type = ADDR_INET;
+ route_to_self->address.ipv4 = ((Sockaddr4 *)addr.get())->sin_addr.s_addr;
+ } else if (addr->sa_family == AF_INET6) {
+ route_to_self->address_type = ADDR_INET6;
+ route_to_self->address.ipv6 = ((Sockaddr6 *)addr.get())->sin6_addr;
+ }
+
+ // Fill remaining payload fields
+ strcpy(route_to_self->symbolic_or_connid, identifier);
+ route_to_self->cost = 1;
+ route_to_self->len = prefix.getPrefixLength();
+
+ // Allocate and fill the header
+ route_to_self->command_id = ADD_ROUTE;
+ route_to_self->message_type = REQUEST_LIGHT;
+ route_to_self->length = 1;
+ // route_to_self->seq_num not needed for now
+
+ send((uint8_t *)route_to_self, sizeof(RouteToSelfCommand),
+ [route_to_self]() { delete route_to_self; });
+}
+
+} // namespace core
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h
new file mode 100755
index 000000000..e57fae105
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class HicnForwarderInterface
+ : public ForwarderInterface<HicnForwarderInterface, SocketConnector> {
+ public:
+ union addressLight {
+ uint32_t ipv4;
+ struct in6_addr ipv6;
+ };
+
+ struct route_to_self_command {
+ uint8_t messageType;
+ uint8_t commandID;
+ uint16_t length;
+ uint32_t seqNum;
+ char symbolicOrConnid[16];
+ union addressLight address;
+ uint16_t cost;
+ uint8_t addressType;
+ uint8_t len;
+ };
+
+ using route_to_self_command = struct route_to_self_command;
+ using ConnectorType = SocketConnector;
+
+ HicnForwarderInterface(SocketConnector &connector);
+
+ ~HicnForwarderInterface();
+
+ void connect(bool is_consumer);
+
+ void registerRoute(Prefix &prefix);
+
+ std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+ static constexpr std::uint16_t interface_mtu = 1500;
+};
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/hicn_memif_api.c b/libtransport/src/hicn/transport/core/hicn_memif_api.c
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/hicn_memif_api.c
diff --git a/libtransport/src/hicn/transport/core/interest.cc b/libtransport/src/hicn/transport/core/interest.cc
new file mode 100755
index 000000000..ff4a5bb34
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/interest.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/interest.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/hash.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+}
+
+#include <cstring>
+#include <memory>
+
+namespace transport {
+
+namespace core {
+
+Interest::Interest(const Name &interest_name, Packet::Format format)
+ : Packet(format) {
+ if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+ interest_name.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+Interest::Interest(hicn_format_t format) : Interest(base_name, format) {}
+
+Interest::Interest(const uint8_t *buffer, std::size_t size)
+ : Packet(buffer, size) {
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+Interest::Interest(MemBufPtr &&buffer) : Packet(std::move(buffer)) {
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+Interest::Interest(Interest &&other_interest)
+ : Packet(std::move(other_interest)) {
+ name_ = std::move(other_interest.name_);
+}
+
+Interest::~Interest() {}
+
+const Name &Interest::getName() const {
+ if (!name_) {
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ (hicn_name_t *)name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ }
+
+ return name_;
+}
+
+Name &Interest::getWritableName() {
+ if (!name_) {
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ (hicn_name_t *)name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ }
+
+ return name_;
+}
+
+Interest &Interest::setName(const Name &name) {
+ if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+ name.getStructReference()) < 0) {
+ throw errors::RuntimeException("Error setting interest name.");
+ }
+
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
+ return *this;
+}
+
+Interest &Interest::setName(Name &&name) {
+ if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+ name.getStructReference()) < 0) {
+ throw errors::RuntimeException("Error setting interest name.");
+ }
+
+ if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+ name_.getStructReference()) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
+ return *this;
+}
+
+void Interest::setLocator(const ip_address_t &ip_address) {
+ if (hicn_interest_set_locator(format_, (hicn_header_t *)packet_start_,
+ &ip_address) < 0) {
+ throw errors::RuntimeException("Error setting interest locator.");
+ }
+
+ return;
+}
+
+ip_address_t Interest::getLocator() const {
+ ip_address_t ip;
+
+ if (hicn_interest_get_locator(format_, (hicn_header_t *)packet_start_, &ip) <
+ 0) {
+ throw errors::RuntimeException("Error getting interest locator.");
+ }
+
+ return ip;
+}
+
+void Interest::resetForHash() {
+ if (hicn_interest_reset_for_hash(
+ format_, reinterpret_cast<hicn_header_t *>(packet_start_)) < 0) {
+ throw errors::RuntimeException(
+ "Error resetting interest fields for hash computation.");
+ }
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/interest.h b/libtransport/src/hicn/transport/core/interest.h
new file mode 100755
index 000000000..75fcba8eb
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/interest.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/object_pool.h>
+
+namespace transport {
+
+namespace core {
+
+class Interest
+ : public Packet /*, public std::enable_shared_from_this<Interest>*/ {
+ public:
+ using Ptr = utils::ObjectPool<Interest>::Ptr;
+
+ Interest(Packet::Format format = HF_INET6_TCP);
+
+ Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP);
+
+ Interest(const uint8_t *buffer, std::size_t size);
+ Interest(MemBufPtr &&buffer);
+
+ /*
+ * Enforce zero-copy.
+ */
+ Interest(const Interest &other_interest) = delete;
+ Interest &operator=(const Interest &other_interest) = delete;
+
+ Interest(Interest &&other_interest);
+
+ ~Interest() override;
+
+ const Name &getName() const;
+
+ Name &getWritableName();
+
+ Interest &setName(const Name &name);
+
+ Interest &setName(Name &&name);
+
+ void setLocator(const ip_address_t &ip_address) override;
+
+ ip_address_t getLocator() const override;
+
+ private:
+ void resetForHash() override;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/key_locator.cc b/libtransport/src/hicn/transport/core/key_locator.cc
new file mode 100755
index 000000000..509fc35ff
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/key_locator.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/key_locator.h>
+
+namespace transport {
+
+namespace core {
+
+KeyLocator::KeyLocator() : type_(KeyLocatorType::UNKNOWN) {}
+
+KeyLocator::KeyLocator(KeyLocatorType type, Name &name)
+ : type_(type), name_(name) {}
+
+Name &KeyLocator::getName() { return name_; }
+
+void KeyLocator::setName(Name &name) { name_ = name; }
+
+void KeyLocator::setType(KeyLocatorType type) { type_ = type; }
+
+KeyLocatorType KeyLocator::getType() { return type_; }
+
+void KeyLocator::clear() {
+ type_ = KeyLocatorType::UNKNOWN;
+ name_.clear();
+}
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/key_locator.h b/libtransport/src/hicn/transport/core/key_locator.h
new file mode 100755
index 000000000..ae3a4ab08
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/key_locator.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/key_locator_type.h>
+#include <hicn/transport/core/name.h>
+
+namespace transport {
+
+namespace core {
+
+class KeyLocator : public std::enable_shared_from_this<KeyLocator> {
+ public:
+ KeyLocator();
+
+ KeyLocator(KeyLocatorType type, Name &name);
+
+ KeyLocatorType getType();
+
+ void setType(KeyLocatorType type);
+
+ void setName(Name &name);
+
+ Name &getName();
+
+ void clear();
+
+ private:
+ KeyLocatorType type_;
+ Name name_;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/key_locator_type.h b/libtransport/src/hicn/transport/core/key_locator_type.h
new file mode 100755
index 000000000..0c84a43ca
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/key_locator_type.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace core {
+
+enum Type { NAME = 0, KEY_DIGEST = 1, UNKNOWN = 255 };
+
+typedef enum Type KeyLocatorType;
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/manifest.cc b/libtransport/src/hicn/transport/core/manifest.cc
new file mode 100755
index 000000000..3f890f3d0
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest.h>
+
+namespace transport {
+
+namespace core {
+
+std::string ManifestEncoding::manifest_type = std::string("manifest_type");
+
+std::map<ManifestType, std::string> ManifestEncoding::manifest_types = {
+ {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}};
+
+std::string ManifestEncoding::final_chunk_number =
+ std::string("final_chunk_number");
+std::string ManifestEncoding::content_name = std::string("content_name");
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest.h b/libtransport/src/hicn/transport/core/manifest.h
new file mode 100755
index 000000000..767addb2e
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+#include <set>
+
+namespace transport {
+
+namespace core {
+
+using typename core::Name;
+using typename core::Packet;
+using typename core::PayloadType;
+
+template <typename Base, typename FormatTraits, typename ManifestImpl>
+class Manifest : public Base {
+ static_assert(std::is_base_of<Packet, Base>::value,
+ "Base must inherit from packet!");
+
+ public:
+ using Encoder = typename FormatTraits::Encoder;
+ using Decoder = typename FormatTraits::Decoder;
+
+ Manifest()
+ : packet_(new Base(HF_INET6_TCP_AH), nullptr),
+ encoder_(*packet_),
+ decoder_(*packet_) {
+ Base::setPayloadType(PayloadType::MANIFEST);
+ }
+
+ Manifest(const core::Name& name)
+ : packet_(new Base(name, HF_INET6_TCP_AH), nullptr),
+ encoder_(*packet_),
+ decoder_(*packet_) {
+ Base::setPayloadType(PayloadType::MANIFEST);
+ }
+
+ Manifest(typename Base::Ptr&& base)
+ : packet_(std::move(base)), encoder_(*packet_), decoder_(*packet_) {
+ Base::setPayloadType(PayloadType::MANIFEST);
+ }
+
+ template <typename T>
+ Manifest(T&& base)
+ : packet_(new Base(std::move<T&&>(base)), nullptr),
+ encoder_(*packet_),
+ decoder_(*packet_) {
+ Base::setPayloadType(PayloadType::MANIFEST);
+ }
+
+ virtual ~Manifest() = default;
+
+ bool operator==(const Manifest& other) {
+ return this->packet_ == other.packet_;
+ }
+
+ std::size_t estimateManifestSize(std::size_t additional_entries = 0) {
+ return static_cast<ManifestImpl&>(*this).estimateManifestSizeImpl(
+ additional_entries);
+ }
+
+ /*
+ * After the call to encode, users MUST call clear before adding data
+ * to the manifest.
+ */
+ Manifest& encode() { return static_cast<ManifestImpl&>(*this).encodeImpl(); }
+
+ Manifest& decode() {
+ Manifest::decoder_.decode();
+
+ manifest_type_ = decoder_.getManifestType();
+ hash_algorithm_ = decoder_.getHashAlgorithm();
+ is_last_ = decoder_.getIsFinalManifest();
+
+ return static_cast<ManifestImpl&>(*this).decodeImpl();
+ }
+
+ static std::size_t getManifestHeaderSize() {
+ return Encoder::getManifestHeaderSize();
+ }
+
+ Manifest& setManifestType(ManifestType type) {
+ manifest_type_ = type;
+ encoder_.setManifestType(manifest_type_);
+ return *this;
+ }
+
+ Manifest& setHashAlgorithm(HashAlgorithm hash_algorithm) {
+ hash_algorithm_ = hash_algorithm;
+ encoder_.setHashAlgorithm(hash_algorithm_);
+ return *this;
+ }
+
+ HashAlgorithm getHashAlgorithm() { return hash_algorithm_; }
+
+ ManifestType getManifestType() const { return manifest_type_; }
+
+ bool isFinalManifest() const { return is_last_; }
+
+ Manifest& setVersion(ManifestVersion version) {
+ encoder_.setVersion(version);
+ return *this;
+ }
+
+ Manifest& setFinalBlockNumber(std::uint32_t final_block_number) {
+ encoder_.setFinalBlockNumber(final_block_number);
+ return *this;
+ }
+
+ uint32_t getFinalBlockNumber() const {
+ return decoder_.getFinalBlockNumber();
+ }
+
+ ManifestVersion getVersion() const { return decoder_.getVersion(); }
+
+ Manifest& setFinalManifest(bool is_final_manifest) {
+ encoder_.setIsFinalManifest(is_final_manifest);
+ is_last_ = is_final_manifest;
+ return *this;
+ }
+
+ Manifest& clear() {
+ encoder_.clear();
+ decoder_.clear();
+ return *this;
+ }
+
+ void setSignatureSize(std::size_t size_bits) {
+ Packet::setSignatureSize(size_bits);
+ encoder_.update();
+ }
+
+ typename Base::Ptr&& getPacket() { return std::move(packet_); }
+
+ protected:
+ typename Base::Ptr packet_;
+ ManifestType manifest_type_;
+ HashAlgorithm hash_algorithm_;
+ bool is_last_;
+
+ Encoder encoder_;
+ Decoder decoder_;
+};
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format.h b/libtransport/src/hicn/transport/core/manifest_format.h
new file mode 100755
index 000000000..1dcf013dc
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/crypto_hasher.h>
+
+#include <cinttypes>
+#include <type_traits>
+#include <unordered_map>
+
+namespace transport {
+
+namespace core {
+
+enum class ManifestFields : uint8_t {
+ VERSION,
+ HASH_ALGORITHM,
+ SEGMENT_CALCULATION_STRATEGY,
+ FINAL_MANIFEST,
+ NAME_HASH_LIST,
+ BASE_NAME
+};
+
+enum class ManifestVersion : uint8_t {
+ VERSION_1 = 1,
+};
+
+enum class ManifestType : uint8_t {
+ INLINE_MANIFEST = 1,
+ FINAL_CHUNK_NUMBER = 2,
+ FLIC_MANIFEST = 3,
+};
+
+enum class HashAlgorithm : uint8_t {
+ SHA_256 = static_cast<uint8_t>(utils::CryptoHashType::SHA_256),
+ SHA_512 = static_cast<uint8_t>(utils::CryptoHashType::SHA_512),
+ CRC32C = static_cast<uint8_t>(utils::CryptoHashType::CRC32C),
+};
+
+enum class NextSegmentCalculationStrategy : uint8_t {
+ INCREMENTAL = 1,
+};
+
+template <typename T>
+struct format_traits {
+ using Encoder = typename T::Encoder;
+ using Decoder = typename T::Decoder;
+ using HashType = typename T::HashType;
+ using HashList = typename T::HashList;
+};
+
+class Packet;
+
+template <typename Implementation>
+class ManifestEncoder {
+ public:
+ virtual ~ManifestEncoder() = default;
+
+ ManifestEncoder encode() {
+ return static_cast<Implementation&>(*this).encodeImpl();
+ }
+
+ ManifestEncoder& clear() {
+ return static_cast<Implementation&>(*this).clearImpl();
+ }
+
+ ManifestEncoder& setManifestType(ManifestType type) {
+ return static_cast<Implementation&>(*this).setManifestTypeImpl(type);
+ }
+
+ ManifestEncoder& setHashAlgorithm(HashAlgorithm hash) {
+ return static_cast<Implementation&>(*this).setHashAlgorithmImpl(hash);
+ }
+
+ ManifestEncoder& setFinalChunkNumber(uint32_t final_chunk) {
+ return static_cast<Implementation&>(*this).setFinalChunkImpl(final_chunk);
+ }
+
+ ManifestEncoder& setNextSegmentCalculationStrategy(
+ NextSegmentCalculationStrategy strategy) {
+ return static_cast<Implementation&>(*this)
+ .setNextSegmentCalculationStrategyImpl(strategy);
+ }
+
+ template <
+ typename T,
+ typename = std::enable_if_t<std::is_same<
+ std::remove_const_t<std::remove_reference_t<T>>, core::Name>::value>>
+ ManifestEncoder& setBaseName(T&& name) {
+ return static_cast<Implementation&>(*this).setBaseNameImpl(name);
+ }
+
+ template <typename Hash>
+ ManifestEncoder& addSuffixAndHash(uint32_t suffix, Hash&& hash) {
+ return static_cast<Implementation&>(*this).addSuffixAndHashImpl(
+ suffix, std::forward<Hash&&>(hash));
+ }
+
+ ManifestEncoder& setIsFinalManifest(bool is_last) {
+ return static_cast<Implementation&>(*this).setIsFinalManifestImpl(is_last);
+ }
+
+ ManifestEncoder& setVersion(ManifestVersion version) {
+ return static_cast<Implementation&>(*this).setVersionImpl(version);
+ }
+
+ std::size_t estimateSerializedLength(std::size_t number_of_entries) {
+ return static_cast<Implementation&>(*this).estimateSerializedLengthImpl(
+ number_of_entries);
+ }
+
+ ManifestEncoder& update() {
+ return static_cast<Implementation&>(*this).updateImpl();
+ }
+
+ ManifestEncoder& setFinalBlockNumber(std::uint32_t final_block_number) {
+ return static_cast<Implementation&>(*this).setFinalBlockNumberImpl(
+ final_block_number);
+ }
+
+ static std::size_t getManifestHeaderSize() {
+ return Implementation::getManifestHeaderSizeImpl();
+ }
+};
+
+template <typename Implementation>
+class ManifestDecoder {
+ public:
+ virtual ~ManifestDecoder() = default;
+
+ ManifestDecoder& clear() {
+ return static_cast<Implementation&>(*this).clearImpl();
+ }
+
+ void decode() { static_cast<Implementation&>(*this).decodeImpl(); }
+
+ ManifestType getManifestType() const {
+ return static_cast<const Implementation&>(*this).getManifestTypeImpl();
+ }
+
+ HashAlgorithm getHashAlgorithm() const {
+ return static_cast<const Implementation&>(*this).getHashAlgorithmImpl();
+ }
+
+ uint32_t getFinalChunkNumber() const {
+ return static_cast<const Implementation&>(*this).getFinalChunkImpl();
+ }
+
+ NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const {
+ return static_cast<const Implementation&>(*this)
+ .getNextSegmentCalculationStrategyImpl();
+ }
+
+ core::Name getBaseName() const {
+ return static_cast<const Implementation&>(*this).getBaseNameImpl();
+ }
+
+ auto getSuffixHashList() {
+ return static_cast<Implementation&>(*this).getSuffixHashListImpl();
+ }
+
+ bool getIsFinalManifest() const {
+ return static_cast<const Implementation&>(*this).getIsFinalManifestImpl();
+ }
+
+ ManifestVersion getVersion() const {
+ return static_cast<const Implementation&>(*this).getVersionImpl();
+ }
+
+ std::size_t estimateSerializedLength(std::size_t number_of_entries) const {
+ return static_cast<const Implementation&>(*this)
+ .estimateSerializedLengthImpl(number_of_entries);
+ }
+
+ uint32_t getFinalBlockNumber() const {
+ return static_cast<const Implementation&>(*this).getFinalBlockNumberImpl();
+ }
+};
+
+} // namespace core
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.cc b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc
new file mode 100755
index 000000000..f26f20adb
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/endianess.h>
+#include <hicn/transport/utils/literals.h>
+
+namespace transport {
+
+namespace core {
+
+// TODO use preallocated pool of membufs
+FixedManifestEncoder::FixedManifestEncoder(Packet& packet)
+ : packet_(packet),
+ max_size_(Packet::default_mtu - packet_.headerSize()),
+ manifest_(
+ utils::MemBuf::create(Packet::default_mtu - packet_.headerSize())),
+ manifest_header_(
+ reinterpret_cast<ManifestHeader*>(manifest_->writableData())),
+ manifest_entries_(reinterpret_cast<ManifestEntry*>(
+ manifest_->writableData() + sizeof(ManifestHeader))),
+ current_entry_(0) {}
+
+FixedManifestEncoder::~FixedManifestEncoder() {}
+
+FixedManifestEncoder& FixedManifestEncoder::encodeImpl() {
+ packet_.appendPayload(std::move(manifest_));
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::clearImpl() {
+ manifest_ = utils::MemBuf::create(Packet::default_mtu - packet_.headerSize());
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setHashAlgorithmImpl(
+ HashAlgorithm algorithm) {
+ manifest_header_->hash_algorithm = static_cast<uint8_t>(algorithm);
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setManifestTypeImpl(
+ ManifestType manifest_type) {
+ manifest_header_->manifest_type = static_cast<uint8_t>(manifest_type);
+ return *this;
+}
+
+FixedManifestEncoder&
+FixedManifestEncoder::setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy) {
+ manifest_header_->next_segment_strategy = static_cast<uint8_t>(strategy);
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setBaseNameImpl(
+ const core::Name& base_name) {
+ base_name.copyToDestination(
+ reinterpret_cast<uint8_t*>(&manifest_header_->prefix[0]), false);
+ manifest_header_->flags.ipv6 =
+ base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8;
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::addSuffixAndHashImpl(
+ uint32_t suffix, const utils::CryptoHash& hash) {
+ auto _hash = hash.getDigest<std::uint8_t>();
+ addSuffixHashBytes(suffix, _hash.data(), _hash.length());
+ return *this;
+}
+
+void FixedManifestEncoder::addSuffixHashBytes(uint32_t suffix,
+ const uint8_t* hash,
+ std::size_t length) {
+ manifest_entries_[current_entry_].suffix = utils::hton(suffix);
+ // std::copy(hash, hash + length,
+ // manifest_entries_[current_entry_].hash);
+ std::memcpy(
+ reinterpret_cast<uint8_t*>(manifest_entries_[current_entry_].hash), hash,
+ length);
+
+ manifest_header_->number_of_entries++;
+ current_entry_++;
+
+ if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) {
+ throw errors::RuntimeException("Manifest size exceeded the packet MTU!");
+ }
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setIsFinalManifestImpl(
+ bool is_last) {
+ manifest_header_->flags.is_last = static_cast<uint8_t>(is_last);
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setVersionImpl(
+ ManifestVersion version) {
+ manifest_header_->version = static_cast<uint8_t>(version);
+ return *this;
+}
+
+std::size_t FixedManifestEncoder::estimateSerializedLengthImpl(
+ std::size_t additional_entries) {
+ return sizeof(ManifestHeader) +
+ (manifest_header_->number_of_entries + additional_entries) *
+ sizeof(ManifestEntry);
+}
+
+FixedManifestEncoder& FixedManifestEncoder::updateImpl() {
+ max_size_ = Packet::default_mtu - packet_.headerSize();
+ manifest_header_ = reinterpret_cast<ManifestHeader*>(
+ const_cast<uint8_t*>(packet_.getPayload().data()));
+ manifest_entries_ = reinterpret_cast<ManifestEntry*>(
+ const_cast<uint8_t*>(packet_.getPayload().data()) +
+ sizeof(ManifestHeader));
+ return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setFinalBlockNumberImpl(
+ std::uint32_t final_block_number) {
+ manifest_header_->final_block_number = utils::hton(final_block_number);
+ return *this;
+}
+
+std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() {
+ return sizeof(ManifestHeader);
+}
+
+FixedManifestDecoder::FixedManifestDecoder(Packet& packet)
+ : packet_(packet),
+ manifest_header_(reinterpret_cast<ManifestHeader*>(
+ const_cast<uint8_t*>(packet_.getPayload().data()))),
+ manifest_entries_(reinterpret_cast<ManifestEntry*>(
+ const_cast<uint8_t*>(packet_.getPayload().data()) +
+ sizeof(ManifestHeader))) {}
+
+FixedManifestDecoder::~FixedManifestDecoder() {}
+
+void FixedManifestDecoder::decodeImpl() {
+ std::size_t packet_size = packet_.payloadSize();
+
+ if (packet_size < sizeof(ManifestHeader) ||
+ packet_size < estimateSerializedLengthImpl()) {
+ throw errors::RuntimeException(
+ "The packet does not match expected manifest size.");
+ }
+}
+
+FixedManifestDecoder& FixedManifestDecoder::clearImpl() { return *this; }
+
+ManifestType FixedManifestDecoder::getManifestTypeImpl() const {
+ return static_cast<ManifestType>(manifest_header_->manifest_type);
+}
+
+HashAlgorithm FixedManifestDecoder::getHashAlgorithmImpl() const {
+ return static_cast<HashAlgorithm>(manifest_header_->hash_algorithm);
+}
+
+NextSegmentCalculationStrategy
+FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+ return static_cast<NextSegmentCalculationStrategy>(
+ manifest_header_->next_segment_strategy);
+}
+
+typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() {
+ typename Fixed::SuffixList hash_list;
+
+ for (int i = 0; i < manifest_header_->number_of_entries; i++) {
+ hash_list.insert(hash_list.end(),
+ std::make_pair(utils::ntoh(manifest_entries_[i].suffix),
+ reinterpret_cast<uint8_t*>(
+ &manifest_entries_[i].hash[0])));
+ }
+
+ return hash_list;
+}
+
+core::Name FixedManifestDecoder::getBaseNameImpl() const {
+ if (static_cast<bool>(manifest_header_->flags.ipv6)) {
+ return core::Name(AF_INET6,
+ reinterpret_cast<uint8_t*>(&manifest_header_->prefix));
+ } else {
+ return core::Name(AF_INET,
+ reinterpret_cast<uint8_t*>(&manifest_header_->prefix));
+ }
+}
+
+bool FixedManifestDecoder::getIsFinalManifestImpl() const {
+ return static_cast<bool>(manifest_header_->flags.is_last);
+}
+
+ManifestVersion FixedManifestDecoder::getVersionImpl() const {
+ return static_cast<ManifestVersion>(manifest_header_->version);
+}
+
+std::size_t FixedManifestDecoder::estimateSerializedLengthImpl(
+ std::size_t additional_entries) const {
+ return sizeof(ManifestHeader) +
+ (additional_entries + manifest_header_->number_of_entries) *
+ sizeof(ManifestEntry);
+}
+
+uint32_t FixedManifestDecoder::getFinalBlockNumberImpl() const {
+ return utils::ntoh(manifest_header_->final_block_number);
+}
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.h b/libtransport/src/hicn/transport/core/manifest_format_fixed.h
new file mode 100755
index 000000000..66825e2f4
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_fixed.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/packet.h>
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |Version| MType |HashAlg|NextStr| Flags |NumberOfEntries|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Final Block Number |
+// +---------------------------------------------------------------|
+// | |
+// + +
+// | |
+// + Prefix +
+// | |
+// + +
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Suffix |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Hash Value |
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class FixedManifestEncoder;
+class FixedManifestDecoder;
+class Packet;
+
+struct Fixed {
+ using Encoder = FixedManifestEncoder;
+ using Decoder = FixedManifestDecoder;
+ using HashType = utils::CryptoHash;
+ using SuffixList = std::list<std::pair<std::uint32_t, std::uint8_t*>>;
+};
+
+struct Flags {
+ std::uint8_t ipv6 : 1;
+ std::uint8_t is_last : 1;
+ std::uint8_t unused : 6;
+};
+
+struct ManifestEntry {
+ std::uint32_t suffix;
+ std::uint32_t hash[8];
+};
+
+struct ManifestHeader {
+ std::uint8_t version : 4;
+ std::uint8_t manifest_type : 4;
+ std::uint8_t hash_algorithm : 4;
+ std::uint8_t next_segment_strategy : 4;
+ Flags flags;
+ std::uint8_t number_of_entries;
+ std::uint32_t final_block_number;
+ std::uint32_t prefix[4];
+ ManifestEntry entries[0];
+};
+
+static const constexpr std::uint8_t manifest_version = 1;
+
+class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
+ public:
+ FixedManifestEncoder(Packet& packet);
+
+ ~FixedManifestEncoder();
+
+ FixedManifestEncoder& encodeImpl();
+
+ FixedManifestEncoder& clearImpl();
+
+ FixedManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+ FixedManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+ FixedManifestEncoder& setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy);
+
+ FixedManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+ FixedManifestEncoder& addSuffixAndHashImpl(uint32_t suffix,
+ const utils::CryptoHash& hash);
+
+ FixedManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+ FixedManifestEncoder& setVersionImpl(ManifestVersion version);
+
+ std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0);
+
+ FixedManifestEncoder& updateImpl();
+
+ FixedManifestEncoder& setFinalBlockNumberImpl(
+ std::uint32_t final_block_number);
+
+ static std::size_t getManifestHeaderSizeImpl();
+
+ private:
+ void addSuffixHashBytes(uint32_t suffix, const uint8_t* hash,
+ std::size_t length);
+
+ Packet& packet_;
+ std::size_t max_size_;
+ std::unique_ptr<utils::MemBuf> manifest_;
+ ManifestHeader* manifest_header_;
+ ManifestEntry* manifest_entries_;
+ std::size_t current_entry_;
+};
+
+class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
+ public:
+ FixedManifestDecoder(Packet& packet);
+
+ ~FixedManifestDecoder();
+
+ void decodeImpl();
+
+ FixedManifestDecoder& clearImpl();
+
+ ManifestType getManifestTypeImpl() const;
+
+ HashAlgorithm getHashAlgorithmImpl() const;
+
+ NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+ typename Fixed::SuffixList getSuffixHashListImpl();
+
+ core::Name getBaseNameImpl() const;
+
+ bool getIsFinalManifestImpl() const;
+
+ std::size_t estimateSerializedLengthImpl(
+ std::size_t additional_entries = 0) const;
+
+ ManifestVersion getVersionImpl() const;
+
+ uint32_t getFinalBlockNumberImpl() const;
+
+ private:
+ Packet& packet_;
+ ManifestHeader* manifest_header_;
+ ManifestEntry* manifest_entries_;
+};
+
+} // namespace core
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc
new file mode 100755
index 000000000..512cdba5b
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/portability/transport_portability.h>
+
+#include <array>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+
+template <typename T>
+TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) {
+ if (pointer == nullptr) {
+ throw errors::NullPointerException();
+ }
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE void setValueToJson(Json::Value& root, EnumType value) {
+ root[JSONKey<EnumType>::key] = static_cast<uint8_t>(value);
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(const Json::Value& root) {
+ return static_cast<EnumType>(root[JSONKey<EnumType>::key].asUInt());
+};
+
+} // namespace
+
+JSONManifestEncoder::JSONManifestEncoder(Packet& packet) : packet_(packet) {}
+
+JSONManifestEncoder::~JSONManifestEncoder() {}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::encodeImpl() {
+ Json::StreamWriterBuilder writer_builder;
+ Json::StreamWriter* fast_writer = writer_builder.newStreamWriter();
+
+ asio::streambuf strbuf;
+ strbuf.prepare(1500);
+ std::ostream stream(&strbuf);
+ fast_writer->write(root_, &stream);
+
+ const uint8_t* buffer = asio::buffer_cast<const uint8_t*>(strbuf.data());
+
+ packet_.setPayload(buffer, strbuf.size());
+
+ delete fast_writer;
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() {
+ root_.clear();
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) {
+ setValueToJson(root_, algorithm);
+ return *this;
+}
+
+JSONManifestEncoder& JSONManifestEncoder::setManifestTypeImpl(
+ ManifestType manifest_type) {
+ setValueToJson(root_, manifest_type);
+ return *this;
+}
+
+JSONManifestEncoder& JSONManifestEncoder::setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy) {
+ setValueToJson(root_, strategy);
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) {
+ root_[JSONKey<core::Name>::key] = base_name.toString().c_str();
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix,
+ const utils::CryptoHash& hash) {
+ throw errors::NotImplementedException();
+ // Json::Value value(Json::arrayValue);
+ // value.append(Json::Value(suffix));
+ // value.append(Json::Value(Json::Value::UInt64 (hash)));
+ // root_[JSONKey<SuffixHashList>::key].append(value);
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) {
+ root_[JSONKey<bool>::final_manifest] = is_last;
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setVersionImpl(ManifestVersion version) {
+ setValueToJson(root_, version);
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setSuffixHashListImpl(
+ const typename JSON::SuffixList& name_hash_list) {
+ throw errors::NotImplementedException();
+ // for (auto &suffix : name_hash_list) {
+ // addSuffixAndHashImpl(suffix.first, suffix.second);
+ // }
+ //
+ // return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestEncoder::estimateSerializedLengthImpl(
+ std::size_t number_of_entries) {
+ Json::StreamWriterBuilder writer_builder;
+ Json::StreamWriter* fast_writer = writer_builder.newStreamWriter();
+
+ asio::streambuf strbuf;
+ strbuf.prepare(1500);
+ std::ostream stream(&strbuf);
+ fast_writer->write(root_, &stream);
+
+ return strbuf.size();
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::updateImpl() {
+ throw errors::NotImplementedException();
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setFinalBlockNumberImpl(std::uint32_t final_block_number) {
+ throw errors::NotImplementedException();
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestEncoder::getManifestHeaderSizeImpl() {
+ return 0;
+}
+
+JSONManifestDecoder::JSONManifestDecoder(Packet& packet) : packet_(packet) {}
+
+JSONManifestDecoder::~JSONManifestDecoder() {}
+
+TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl() {
+ auto array = packet_.getPayload();
+ auto payload = array.data();
+ auto payload_size = array.length();
+
+ Json::CharReaderBuilder reader_builder;
+ Json::CharReader* reader = reader_builder.newCharReader();
+ std::string errors;
+
+ if (!reader->parse((char*)payload, (char*)payload + payload_size, &root_,
+ &errors)) {
+ TRANSPORT_LOGE("Error parsing manifest!");
+ TRANSPORT_LOGE("%s", errors.c_str());
+
+ delete reader;
+
+ throw errors::MalformedPacketException();
+ }
+
+ delete reader;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() {
+ root_.clear();
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestType
+JSONManifestDecoder::getManifestTypeImpl() const {
+ return getValueFromJson<ManifestType>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE HashAlgorithm
+JSONManifestDecoder::getHashAlgorithmImpl() const {
+ return getValueFromJson<HashAlgorithm>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy
+JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+ return getValueFromJson<NextSegmentCalculationStrategy>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE typename JSON::SuffixList
+JSONManifestDecoder::getSuffixHashListImpl() {
+ throw errors::NotImplementedException();
+ // SuffixHashList hash_list;
+ //
+ // Json::Value &array = root_[JSONKey<SuffixHashList>::key];
+ //
+ // for (Json::Value::ArrayIndex i = 0;
+ // i != array.size();
+ // i++) {
+ // hash_list[array[i][0].asUInt()] = array[i][1].asUInt64();
+ // }
+ //
+ // return hash_list;
+}
+
+TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl()
+ const {
+ return core::Name(root_[JSONKey<core::Name>::key].asCString());
+}
+
+TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl()
+ const {
+ return root_[JSONKey<bool>::final_manifest].asBool();
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestVersion
+JSONManifestDecoder::getVersionImpl() const {
+ return getValueFromJson<ManifestVersion>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t
+JSONManifestDecoder::getFinalBlockNumberImpl() const {
+ return 0;
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h
new file mode 100755
index 000000000..39f0cf351
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+#if defined(__APPLE__) || defined(__ANDROID__)
+#include <json/json.h>
+#else
+#include <jsoncpp/json/json.h>
+#endif /* __APPLE__ || __ANDROID__*/
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+class JSONManifestEncoder;
+class JSONManifestDecoder;
+class Packet;
+
+struct JSON {
+ using Encoder = JSONManifestEncoder;
+ using Decoder = JSONManifestDecoder;
+ using HashType = utils::CryptoHash;
+ using SuffixList = std::unordered_map<std::uint32_t, std::uint8_t*>;
+};
+
+template <typename T>
+struct JSONKey;
+
+template <>
+struct JSONKey<ManifestVersion> {
+ static const constexpr char* key = "manifest_version";
+};
+
+template <>
+struct JSONKey<HashAlgorithm> {
+ static const constexpr char* key = "hash_algorithm";
+};
+
+template <>
+struct JSONKey<ManifestType> {
+ static const constexpr char* key = "manifest_type";
+};
+
+template <>
+struct JSONKey<NextSegmentCalculationStrategy> {
+ static const constexpr char* key = "next_segment_strategy";
+};
+
+template <>
+struct JSONKey<typename JSON::SuffixList> {
+ static const constexpr char* key = "suffix_hash_list";
+};
+
+template <>
+struct JSONKey<core::Name> {
+ static const constexpr char* key = "base_name";
+};
+
+template <>
+struct JSONKey<bool> {
+ static const constexpr char* final_manifest = "final_manifest";
+};
+
+class JSONManifestEncoder : public ManifestEncoder<JSONManifestEncoder> {
+ public:
+ JSONManifestEncoder(Packet& packet);
+
+ ~JSONManifestEncoder() override;
+
+ JSONManifestEncoder& encodeImpl();
+
+ JSONManifestEncoder& clearImpl();
+
+ JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+ JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+ JSONManifestEncoder& setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy);
+
+ JSONManifestEncoder& setSuffixHashListImpl(
+ const typename JSON::SuffixList& name_hash_list);
+
+ JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+ JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix,
+ const utils::CryptoHash& hash);
+
+ JSONManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+ JSONManifestEncoder& setVersionImpl(ManifestVersion version);
+
+ std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries);
+
+ JSONManifestEncoder& updateImpl();
+
+ JSONManifestEncoder& setFinalBlockNumberImpl(
+ std::uint32_t final_block_number);
+
+ static std::size_t getManifestHeaderSizeImpl();
+
+ private:
+ Packet& packet_;
+ Json::Value root_;
+};
+
+class JSONManifestDecoder : public ManifestDecoder<JSONManifestDecoder> {
+ public:
+ JSONManifestDecoder(Packet& packet);
+
+ ~JSONManifestDecoder() override;
+
+ void decodeImpl();
+
+ JSONManifestDecoder& clearImpl();
+
+ ManifestType getManifestTypeImpl() const;
+
+ HashAlgorithm getHashAlgorithmImpl() const;
+
+ uint32_t getFinalChunkImpl() const;
+
+ NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+ typename JSON::SuffixList getSuffixHashListImpl();
+
+ core::Name getBaseNameImpl() const;
+
+ bool getIsFinalManifestImpl() const;
+
+ std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries) const;
+
+ ManifestVersion getVersionImpl() const;
+
+ uint32_t getFinalBlockNumberImpl() const;
+
+ private:
+ Packet& packet_;
+ Json::Value root_;
+};
+
+} // namespace core
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc
new file mode 100755
index 000000000..d0365d2fe
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format_json_libparc_deprecated.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/transport_portability.h>
+
+extern "C" {
+#include <parc/algol/parc_Memory.h>
+}
+
+namespace transport {
+
+namespace core {
+
+namespace {
+
+template <typename T>
+TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) {
+ if (pointer == nullptr) {
+ throw errors::NullPointerException();
+ }
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE void setValueToJson(PARCJSON* root, EnumType value) {
+ parcJSON_AddInteger(root, JSONKey<EnumType>::key,
+ static_cast<int64_t>(value));
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(PARCJSON* root) {
+ checkPointer(root);
+
+ PARCJSONValue* value = parcJSON_GetValueByName(root, JSONKey<EnumType>::key);
+
+ EnumType ret = static_cast<EnumType>(parcJSONValue_GetInteger(value));
+ // parcJSONValue_Release(&value);
+
+ return ret;
+};
+
+} // namespace
+
+JSONManifestEncoder::JSONManifestEncoder() : root_(parcJSON_Create()) {
+ parcJSON_Acquire(root_);
+}
+
+JSONManifestEncoder::~JSONManifestEncoder() {
+ if (root_) {
+ parcJSON_Release(&root_);
+ }
+}
+
+TRANSPORT_ALWAYS_INLINE SONManifestEncoder& JSONManifestEncoder::encodeImpl(
+ Packet& packet) {
+ char* json_string = parcJSON_ToString(root_);
+ packet.setPayload(reinterpret_cast<uint8_t*>(json_string),
+ std::strlen(json_string));
+ parcMemory_Deallocate(&json_string);
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() {
+ if (root_) {
+ parcJSON_Release(&root_);
+ }
+
+ root_ = parcJSON_Create();
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) {
+ setValueToJson(root_, algorithm);
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setManifestTypeImpl(ManifestType manifest_type) {
+ setValueToJson(root_, manifest_type);
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy) {
+ setValueToJson(root_, strategy);
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) {
+ parcJSON_AddString(root_, JSONKey<core::Name>::key,
+ base_name.toString().c_str());
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix,
+ utils::CryptoHash& hash) {
+ throw errors::NotImplementedException();
+ // PARCJSONValue *value = parcJSON_GetValueByName(root_,
+ // JSONKey<SuffixHashList>::key);
+ //
+ // // Create the pair to store in the array.
+ // // It will be segment number + Hash of the segment
+ // PARCJSONArray * pair = parcJSONArray_Create();
+ //
+ // PARCJSONValue *v = parcJSONValue_CreateFromInteger(suffix);
+ // parcJSONArray_AddValue(pair, v);
+ // parcJSONValue_Release(&v);
+ //
+ // v = parcJSONValue_CreateFromInteger(hash);
+ // parcJSONArray_AddValue(pair, v);
+ // parcJSONValue_Release(&v);
+ //
+ // if (value == nullptr /* || !parcJSONValue_IsArray(value) */) {
+ // // Create the array
+ // PARCJSONArray *array = parcJSONArray_Create();
+ // parcJSON_AddArray(root_,
+ // JSONKey<SuffixHashList>::key,
+ // array);
+ // parcJSONArray_Release(&array);
+ //
+ // value = parcJSON_GetValueByName(root_, JSONKey<SuffixHashList>::key);
+ // }
+ //
+ // v = parcJSONValue_CreateFromJSONArray(pair);
+ // parcJSONArray_AddValue(parcJSONValue_GetArray(value), v);
+ // parcJSONValue_Release(&v);
+ //
+ // parcJSONArray_Release(&pair);
+ // // parcJSONValue_Release(&value);
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) {
+ parcJSON_AddBoolean(root_, JSONKey<bool>::final_manifest, is_last);
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setSuffixHashListImpl(
+ const SuffixHashList& name_hash_list) {
+ for (auto& suffix : name_hash_list) {
+ addSuffixAndHashImpl(suffix.first, suffix.second);
+ }
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::JSONManifestDecoder()
+ : root_(nullptr) {}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::~JSONManifestDecoder() {
+ if (root_) {
+ parcJSON_Release(&root_);
+ }
+}
+
+TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl(
+ const uint8_t* payload, std::size_t payload_size) {
+ PARCBuffer* b = parcBuffer_Wrap(const_cast<uint8_t*>(payload), payload_size,
+ 0, payload_size);
+ clearImpl();
+
+ root_ = parcJSON_ParseBuffer(b);
+ parcBuffer_Release(&b);
+
+ char* str = parcJSON_ToString(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() {
+ if (root_) {
+ parcJSON_Release(&root_);
+ }
+
+ return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestType
+JSONManifestDecoder::getManifestTypeImpl() const {
+ return getValueFromJson<ManifestType>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE HashAlgorithm
+JSONManifestDecoder::getHashAlgorithmImpl() const {
+ return getValueFromJson<HashAlgorithm>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy
+JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+ return getValueFromJson<NextSegmentCalculationStrategy>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE SuffixHashList
+JSONManifestDecoder::getSuffixHashListImpl() {
+ throw errors::NotImplementedException();
+ // SuffixHashList hash_list;
+ //
+ // char * str = parcJSON_ToString(root_);
+ //
+ // PARCJSONValue *value = parcJSON_GetValueByName(root_,
+ // JSONKey<SuffixHashList>::key);
+ //
+ // if (value == nullptr || !parcJSONValue_IsArray(value)) {
+ // throw errors::RuntimeException("Manifest does not contain suffix-hash
+ // list");
+ // }
+ //
+ // PARCJSONArray *array = parcJSONValue_GetArray(value);
+ // std::size_t array_size = parcJSONArray_GetLength(array);
+ //
+ // for (std::size_t i = 0; i < array_size; i++) {
+ // PARCJSONValue *v = parcJSONArray_GetValue(array, i);
+ // checkPointer(v);
+ // PARCJSONArray *a = parcJSONValue_GetArray(v);
+ // PARCJSONValue *_suffix = parcJSONArray_GetValue(a, 0);
+ // PARCJSONValue *_hash = parcJSONArray_GetValue(a, 1);
+ //
+ // uint32_t value1 =
+ // static_cast<uint32_t>(parcJSONValue_GetInteger(_suffix)); uint64_t
+ // value2 = static_cast<uint64_t>(parcJSONValue_GetInteger(_hash));
+ //
+ // hash_list[static_cast<uint32_t>(parcJSONValue_GetInteger(_suffix))] =
+ // static_cast<uint64_t>(parcJSONValue_GetInteger(_hash));
+ //
+ //// parcJSONValue_Release(&_hash);
+ //// parcJSONValue_Release(&_suffix);
+ //// parcJSONArray_Release(&a);
+ //// parcJSONValue_Release(&v);
+ // }
+ //
+ //// parcJSONArray_Release(&array);
+ //// parcJSONValue_Release(&value);
+ //
+ // char * str2 = parcJSON_ToString(root_);
+ //
+ // return hash_list;
+}
+
+TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl()
+ const {
+ checkPointer(root_);
+ PARCJSONValue* value =
+ parcJSON_GetValueByName(root_, JSONKey<core::Name>::key);
+
+ PARCBuffer* b = parcJSONValue_GetString(value);
+ char* string = parcBuffer_ToString(b);
+
+ core::Name ret(string);
+
+ // parcJSONValue_Release(&value);
+ parcMemory_Deallocate(&string);
+
+ return ret;
+}
+
+TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl() {
+ checkPointer(root_);
+ PARCJSONValue* value =
+ parcJSON_GetValueByName(root_, JSONKey<bool>::final_manifest);
+
+ bool ret = parcJSONValue_GetBoolean(value);
+
+ // parcJSONValue_Release(&value);
+
+ return ret;
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestDecoder::estimateSerializedLengthImpl(
+ std::size_t number_of_entries) {
+ return 0;
+}
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h
new file mode 100755
index 000000000..28c6c1b40
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+extern "C" {
+#include <parc/algol/parc_JSON.h>
+}
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+class JSONManifestEncoder;
+class JSONManifestDecoder;
+class Packet;
+
+struct JSON {
+ using Encoder = JSONManifestEncoder;
+ using Decoder = JSONManifestDecoder;
+};
+
+template <typename T>
+struct JSONKey;
+
+template <>
+struct JSONKey<HashAlgorithm> {
+ static const constexpr char* key = "hash_algorithm";
+};
+
+template <>
+struct JSONKey<ManifestType> {
+ static const constexpr char* key = "manifest_type";
+};
+
+template <>
+struct JSONKey<NextSegmentCalculationStrategy> {
+ static const constexpr char* key = "next_segment_strategy";
+};
+
+template <>
+struct JSONKey<NameHashList> {
+ static const constexpr char* key = "name_hash_list";
+};
+
+template <>
+struct JSONKey<SuffixHashList> {
+ static const constexpr char* key = "suffix_hash_list";
+};
+
+template <>
+struct JSONKey<core::Name> {
+ static const constexpr char* key = "base_name";
+};
+
+template <>
+struct JSONKey<bool> {
+ static const constexpr char* final_manifest = "final_manifest";
+};
+
+// template <>
+// struct JSONKey<base_name> {
+// static const std::string key = "name_hash_list";
+//};
+
+// namespace JSONManifestEncoding {
+// static const std::string base_name = "base_name";
+// static const std::string final_chunk_number = "final_chunk_number";
+// static const std::string hash_algorithm = "hash_algorithm";
+// static const std::string manifest_type = "manifest_type";
+// static const std::string name_hash_list = "name_hash_list";
+// static const std::string next_segment_strategy = "next_segment_strategy";
+//}
+
+class JSONManifestEncoder : public ManifestEncoder<JSONManifestEncoder> {
+ public:
+ JSONManifestEncoder();
+
+ ~JSONManifestEncoder();
+
+ JSONManifestEncoder& encodeImpl(Packet& packet);
+
+ JSONManifestEncoder& clearImpl();
+
+ JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+ JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+ JSONManifestEncoder& setNextSegmentCalculationStrategyImpl(
+ NextSegmentCalculationStrategy strategy);
+
+ JSONManifestEncoder& setSuffixHashListImpl(
+ const SuffixHashList& name_hash_list);
+
+ JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+ JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix, uint64_t hash);
+
+ JSONManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+ private:
+ PARCJSON* root_;
+};
+
+class JSONManifestDecoder : public ManifestDecoder<JSONManifestDecoder> {
+ public:
+ JSONManifestDecoder();
+
+ ~JSONManifestDecoder();
+
+ void decodeImpl(const uint8_t* payload, std::size_t payload_size);
+
+ JSONManifestDecoder& clearImpl();
+
+ ManifestType getManifestTypeImpl() const;
+
+ HashAlgorithm getHashAlgorithmImpl() const;
+
+ uint32_t getFinalChunkImpl() const;
+
+ NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+ SuffixHashList getSuffixHashListImpl();
+
+ core::Name getBaseNameImpl() const;
+
+ bool getIsFinalManifestImpl();
+
+ private:
+ PARCJSON* root_;
+};
+
+} // namespace core
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_inline.h b/libtransport/src/hicn/transport/core/manifest_inline.h
new file mode 100755
index 000000000..fd1a9abd3
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/manifest_inline.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest.h>
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <set>
+
+namespace transport {
+
+namespace core {
+
+template <typename Base, typename FormatTraits>
+class ManifestInline
+ : public Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>> {
+ using ManifestBase =
+ Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>>;
+ using HashType = typename FormatTraits::HashType;
+ using SuffixList = typename FormatTraits::SuffixList;
+
+ public:
+ ManifestInline() : ManifestBase() {}
+
+ ManifestInline(const core::Name& name) : ManifestBase(name) {}
+
+ template <typename T>
+ ManifestInline(T&& base) : ManifestBase(std::forward<T&&>(base)) {}
+
+ static TRANSPORT_ALWAYS_INLINE ManifestInline* createManifest(
+ const core::Name& manifest_name, ManifestVersion version,
+ ManifestType type, HashAlgorithm algorithm, bool is_last,
+ const Name& base_name, NextSegmentCalculationStrategy strategy,
+ std::size_t signature_size) {
+ auto manifest = new ManifestInline(manifest_name);
+ manifest->setSignatureSize(signature_size);
+ manifest->setVersion(version);
+ manifest->setManifestType(type);
+ manifest->setHashAlgorithm(algorithm);
+ manifest->setFinalManifest(is_last);
+ manifest->setBaseName(base_name);
+ manifest->setNextSegmentCalculationStrategy(strategy);
+
+ return manifest;
+ }
+
+ ManifestInline& encodeImpl() {
+ ManifestBase::encoder_.encode();
+ return *this;
+ }
+
+ ManifestInline& decodeImpl() {
+ base_name_ = ManifestBase::decoder_.getBaseName();
+ next_segment_strategy_ =
+ ManifestBase::decoder_.getNextSegmentCalculationStrategy();
+ suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList();
+
+ return *this;
+ }
+
+ std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) {
+ return ManifestBase::encoder_.estimateSerializedLength(additional_entries);
+ }
+
+ ManifestInline& setBaseName(const Name& name) {
+ base_name_ = name;
+ ManifestBase::encoder_.setBaseName(base_name_);
+ return *this;
+ }
+
+ const Name& getBaseName() { return base_name_; }
+
+ ManifestInline& addSuffixHash(uint32_t suffix, const HashType& hash) {
+ ManifestBase::encoder_.addSuffixAndHash(suffix, hash);
+ return *this;
+ }
+
+ // Call this function only after the decode function!
+ const SuffixList& getSuffixList() { return suffix_hash_map_; }
+
+ ManifestInline& setNextSegmentCalculationStrategy(
+ NextSegmentCalculationStrategy strategy) {
+ next_segment_strategy_ = strategy;
+ ManifestBase::encoder_.setNextSegmentCalculationStrategy(
+ next_segment_strategy_);
+ return *this;
+ }
+
+ NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() {
+ return next_segment_strategy_;
+ }
+
+ private:
+ core::Name base_name_;
+ NextSegmentCalculationStrategy next_segment_strategy_;
+ SuffixList suffix_hash_map_;
+};
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.c b/libtransport/src/hicn/transport/core/memif_binary_api.c
new file mode 100755
index 000000000..b443b51ce
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/memif_binary_api.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/memif_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+// uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <memif/memif_msg_enum.h>
+
+#define vl_msg_name_crc_list
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+#define vl_typedefs
+#define vl_endianfun
+#define vl_print(handle, ...)
+#define vl_printfun
+#define vl_api_version(n, v) static u32 api_version = (v);
+#define vl_msg_name_crc_list
+#include <memif/memif_all_api_h.h>
+#undef vl_msg_name_crc_list
+#undef vl_api_version
+#undef vl_printfun
+#undef vl_endianfun
+#undef vl_typedefs
+
+/* define message structures */
+#define vl_typedefs
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_memif_api_reply_msg \
+ _(MEMIF_CREATE_REPLY, memif_create_reply) \
+ _(MEMIF_DELETE_REPLY, memif_delete_reply) \
+ _(MEMIF_DETAILS, memif_details)
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t *api) {
+ // Dump all the memif interfaces and return the next to the largest memif id
+ vl_api_memif_dump_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+
+ M(MEMIF_DUMP, mp);
+ api->vpp_api->user_param = malloc(sizeof(uint32_t));
+ *(uint32_t *)(api->vpp_api->user_param) = 0;
+ global_pointers_map[global_pointers_map_index] = api;
+ mp->context = global_pointers_map_index++;
+ global_pointers_map_index %= POINTER_MAP_SIZE;
+
+ vpp_binary_api_send_request(api->vpp_api, mp);
+
+ vpp_binary_api_send_receive_ping(api->vpp_api);
+
+ uint32_t ret = *(uint32_t *)(api->vpp_api->user_param);
+ free(api->vpp_api->user_param);
+
+ return ret;
+}
+
+static void vl_api_memif_details_t_handler(vl_api_memif_details_t *mp) {
+ vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+ uint32_t *last_memif_id = binary_api->vpp_api->user_param;
+ uint32_t current_memif_id = clib_net_to_host_u32(mp->id);
+ if (current_memif_id >= *last_memif_id) {
+ *last_memif_id = current_memif_id + 1;
+ }
+}
+
+int memif_binary_api_create_memif(vpp_plugin_binary_api_t *api,
+ memif_create_params_t *input_params,
+ memif_output_params_t *output_params) {
+ vl_api_memif_create_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+
+ if (input_params->socket_id == ~0) {
+ // invalid socket-id
+ return -1;
+ }
+
+ if (!is_pow2(input_params->ring_size)) {
+ // ring size must be power of 2
+ return -1;
+ }
+
+ if (input_params->rx_queues > 255 || input_params->rx_queues < 1) {
+ // rx queue must be between 1 - 255
+ return -1;
+ }
+
+ if (input_params->tx_queues > 255 || input_params->tx_queues < 1) {
+ // tx queue must be between 1 - 255
+ return -1;
+ }
+
+ api->vpp_api->user_param = output_params;
+
+ /* Construct the API message */
+ M(MEMIF_CREATE, mp);
+
+ global_pointers_map[global_pointers_map_index] = api;
+ mp->context = global_pointers_map_index++;
+ global_pointers_map_index %= POINTER_MAP_SIZE;
+
+ mp->role = input_params->role;
+ mp->mode = input_params->mode;
+ mp->rx_queues = input_params->rx_queues;
+ mp->tx_queues = input_params->tx_queues;
+ mp->id = clib_host_to_net_u32(input_params->id);
+ mp->socket_id = clib_host_to_net_u32(input_params->socket_id);
+ mp->ring_size = clib_host_to_net_u32(input_params->ring_size);
+ mp->buffer_size = clib_host_to_net_u16(input_params->buffer_size);
+
+ int ret = vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return vpp_binary_api_set_int_state(api->vpp_api, output_params->sw_if_index,
+ UP);
+}
+int memif_binary_api_delete_memif(vpp_plugin_binary_api_t *api,
+ uint32_t sw_if_index) {
+ vl_api_memif_delete_t *mp;
+ vpp_plugin_binary_api_t *hm = api;
+
+ /* Construct the API message */
+ M(MEMIF_DELETE, mp);
+
+ global_pointers_map[global_pointers_map_index] = api;
+ mp->context = global_pointers_map_index++;
+ global_pointers_map_index %= POINTER_MAP_SIZE;
+
+ mp->sw_if_index = htonl(sw_if_index);
+
+ return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_memif_create_reply_t_handler(
+ vl_api_memif_create_reply_t *mp) {
+ vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+ memif_output_params_t *params = binary_api->vpp_api->user_param;
+
+ binary_api->vpp_api->ret_val = ntohl(mp->retval);
+ params->sw_if_index = clib_net_to_host_u32(mp->sw_if_index);
+
+ TRANSPORT_LOGI("ret :%d", binary_api->vpp_api->ret_val);
+
+ vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static void vl_api_memif_delete_reply_t_handler(
+ vl_api_memif_delete_reply_t *mp) {
+ vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+
+ binary_api->vpp_api->ret_val = ntohl(mp->retval);
+
+ vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static int memif_binary_api_setup_handlers(
+ vpp_plugin_binary_api_t *binary_api) {
+ vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api;
+#define _(N, n) \
+ vl_msg_api_set_handlers(VL_API_##N + sm->msg_id_base, #n, \
+ vl_api_##n##_t_handler, vl_noop_handler, \
+ vl_api_##n##_t_endian, vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_memif_api_reply_msg;
+#undef _
+ return 0;
+}
+
+vpp_plugin_binary_api_t *memif_binary_api_init(vpp_binary_api_t *api) {
+ vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t));
+ u8 *name = format(0, "memif_%08x%c", api_version, 0);
+ ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name);
+ ret->vpp_api = api;
+ ret->my_client_index = api->my_client_index;
+ memif_binary_api_setup_handlers(ret);
+ return ret;
+}
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.h b/libtransport/src/hicn/transport/core/memif_binary_api.h
new file mode 100755
index 000000000..582aeb1a0
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/memif_binary_api.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/vpp_binary_api.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdint.h"
+
+typedef struct memif_create_params_s {
+ uint8_t role;
+ uint8_t mode;
+ uint8_t rx_queues;
+ uint8_t tx_queues;
+ uint32_t id;
+ uint32_t socket_id;
+ uint8_t secret[24];
+ uint32_t ring_size;
+ uint16_t buffer_size;
+ uint8_t hw_addr[6];
+} memif_create_params_t;
+
+typedef struct memif_output_params_s {
+ uint32_t sw_if_index;
+} memif_output_params_t;
+
+vpp_plugin_binary_api_t* memif_binary_api_init(vpp_binary_api_t* api);
+
+uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t* api);
+
+int memif_binary_api_create_memif(vpp_plugin_binary_api_t* api,
+ memif_create_params_t* input_params,
+ memif_output_params_t* output_params);
+
+int memif_binary_api_delete_memif(vpp_plugin_binary_api_t* api,
+ uint32_t sw_if_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_connector.cc b/libtransport/src/hicn/transport/core/memif_connector.cc
new file mode 100755
index 000000000..7a672314e
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/memif_connector.cc
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/memif_connector.h>
+
+#ifdef __vpp__
+
+#include <sys/epoll.h>
+#include <cstdlib>
+
+#define CANCEL_TIMER 1
+
+namespace transport {
+
+namespace core {
+
+std::once_flag MemifConnector::flag_;
+utils::EpollEventReactor MemifConnector::main_event_reactor_;
+
+MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback,
+ OnReconnect &&on_reconnect_callback,
+ asio::io_service &io_service,
+ std::string app_name)
+ : Connector(),
+ memif_worker_(nullptr),
+ timer_set_(false),
+ send_timer_(std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
+ io_service_(io_service),
+ work_(std::make_unique<asio::io_service::work>(io_service_)),
+ packet_counter_(0),
+ memif_connection_({}),
+ tx_buf_counter_(0),
+ is_connecting_(true),
+ is_reconnection_(false),
+ data_available_(false),
+ enable_burst_(false),
+ app_name_(app_name),
+ receive_callback_(receive_callback),
+ on_reconnect_callback_(on_reconnect_callback),
+ socket_filename_("") {
+ std::call_once(MemifConnector::flag_, &MemifConnector::init, this);
+}
+
+MemifConnector::~MemifConnector() { close(); }
+
+void MemifConnector::init() {
+ /* initialize memory interface */
+ int err = memif_init(controlFdUpdate, const_cast<char *>(app_name_.c_str()),
+ nullptr, nullptr, nullptr);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_init: %s", memif_strerror(err));
+ }
+}
+
+void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
+ TRANSPORT_LOGI("Creating memif");
+
+ memif_id_ = memif_id;
+ socket_filename_ = "/run/vpp/memif.sock";
+
+ createMemif(memif_id, memif_mode, nullptr);
+
+ while (is_connecting_) {
+ MemifConnector::main_event_reactor_.runOneEvent();
+ }
+
+ int err;
+
+ /* get interrupt queue id */
+ int fd = -1;
+ err = memif_get_queue_efd(memif_connection_.conn, 0, &fd);
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_get_queue_efd: %s", memif_strerror(err));
+ return;
+ }
+
+ // Remove fd from main epoll
+ main_event_reactor_.delFileDescriptor(fd);
+
+ // Add fd to epoll of instance
+ event_reactor_.addFileDescriptor(
+ fd, EPOLLIN, [this](const utils::Event &evt) -> int {
+ return onInterrupt(memif_connection_.conn, this, 0);
+ });
+
+ memif_worker_ = std::make_unique<std::thread>(
+ std::bind(&MemifConnector::threadMain, this));
+}
+
+int MemifConnector::createMemif(uint32_t index, uint8_t mode, char *s) {
+ memif_connection_t *c = &memif_connection_;
+
+ /* setting memif connection arguments */
+ memif_conn_args_t args;
+ memset(&args, 0, sizeof(args));
+
+ args.is_master = mode;
+ args.log2_ring_size = MEMIF_LOG2_RING_SIZE;
+ args.buffer_size = MEMIF_BUF_SIZE;
+ args.num_s2m_rings = 1;
+ args.num_m2s_rings = 1;
+ strncpy((char *)args.interface_name, IF_NAME, strlen(IF_NAME));
+ // strncpy((char *) args.instance_name, APP_NAME, strlen(APP_NAME));
+ args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
+ args.socket_filename = (uint8_t *)socket_filename_.c_str();
+
+ TRANSPORT_LOGI("Socket filename: %s", args.socket_filename);
+
+ args.interface_id = index;
+ /* last argument for memif_create (void * private_ctx) is used by user
+ to identify connection. this context is returned with callbacks */
+ int err;
+ /* default interrupt */
+ if (s == nullptr) {
+ err = memif_create(&c->conn, &args, onConnect, onDisconnect, onInterrupt,
+ this);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ throw errors::RuntimeException(memif_strerror(err));
+ }
+ }
+
+ c->index = (uint16_t)index;
+ c->tx_qid = 0;
+ /* alloc memif buffers */
+ c->rx_buf_num = 0;
+ c->rx_bufs = static_cast<memif_buffer_t *>(
+ malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS));
+ c->tx_buf_num = 0;
+ c->tx_bufs = static_cast<memif_buffer_t *>(
+ malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS));
+
+ // memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, 0);
+
+ return 0;
+}
+
+int MemifConnector::deleteMemif() {
+ memif_connection_t *c = &memif_connection_;
+
+ if (c->rx_bufs) {
+ free(c->rx_bufs);
+ }
+
+ c->rx_bufs = nullptr;
+ c->rx_buf_num = 0;
+
+ if (c->tx_bufs) {
+ free(c->tx_bufs);
+ }
+
+ c->tx_bufs = nullptr;
+ c->tx_buf_num = 0;
+
+ int err;
+ /* disconenct then delete memif connection */
+ err = memif_delete(&c->conn);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_delete: %s", memif_strerror(err));
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) {
+ TRANSPORT_LOGI("memif delete fail");
+ }
+
+ return 0;
+}
+
+int MemifConnector::controlFdUpdate(int fd, uint8_t events) {
+ /* convert memif event definitions to epoll events */
+ if (events & MEMIF_FD_EVENT_DEL) {
+ return MemifConnector::main_event_reactor_.delFileDescriptor(fd);
+ }
+
+ uint32_t evt = 0;
+
+ if (events & MEMIF_FD_EVENT_READ) {
+ evt |= EPOLLIN;
+ }
+
+ if (events & MEMIF_FD_EVENT_WRITE) {
+ evt |= EPOLLOUT;
+ }
+
+ if (events & MEMIF_FD_EVENT_MOD) {
+ return MemifConnector::main_event_reactor_.modFileDescriptor(fd, evt);
+ }
+
+ return MemifConnector::main_event_reactor_.addFileDescriptor(
+ fd, evt, [](const utils::Event &evt) -> int {
+ uint32_t event = 0;
+ int memif_err = 0;
+
+ if (evt.events & EPOLLIN) {
+ event |= MEMIF_FD_EVENT_READ;
+ }
+
+ if (evt.events & EPOLLOUT) {
+ event |= MEMIF_FD_EVENT_WRITE;
+ }
+
+ if (evt.events & EPOLLERR) {
+ event |= MEMIF_FD_EVENT_ERROR;
+ }
+
+ memif_err = memif_control_fd_handler(evt.data.fd, event);
+
+ if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_control_fd_handler: %s",
+ memif_strerror(memif_err));
+ }
+
+ return 0;
+ });
+}
+
+int MemifConnector::bufferAlloc(long n, uint16_t qid) {
+ memif_connection_t *c = &memif_connection_;
+ int err;
+ uint16_t r;
+ /* set data pointer to shared memory and set buffer_len to shared mmeory
+ * buffer len */
+ err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGD("memif_buffer_alloc: %s", memif_strerror(err));
+ }
+
+ c->tx_buf_num += r;
+ TRANSPORT_LOGD("allocated %d/%ld buffers, %u free buffers", r, n,
+ MAX_MEMIF_BUFS - c->tx_buf_num);
+ return r;
+}
+
+int MemifConnector::txBurst(uint16_t qid) {
+ memif_connection_t *c = &memif_connection_;
+ int err;
+ uint16_t r;
+ /* inform peer memif interface about data in shared memory buffers */
+ /* mark memif buffers as free */
+ err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err));
+ }
+
+ // err = memif_refill_queue(c->conn, qid, r, 0);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err));
+ c->tx_buf_num -= r;
+ return -1;
+ }
+
+ TRANSPORT_LOGD("tx: %d/%u", r, c->tx_buf_num);
+ c->tx_buf_num -= r;
+ return 0;
+}
+
+void MemifConnector::sendCallback(const std::error_code &ec) {
+ if (TRANSPORT_EXPECT_TRUE(!ec && !is_connecting_)) {
+ doSend();
+ }
+
+ if (output_buffer_.size() > 0) {
+ send_timer_->expiresFromNow(std::chrono::microseconds(50));
+ send_timer_->asyncWait(
+ std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1));
+ } else {
+ timer_set_ = false;
+ }
+}
+
+void MemifConnector::processInputBuffer() {
+ Packet::MemBufPtr ptr;
+
+ while (input_buffer_.pop(ptr)) {
+ receive_callback_(std::move(ptr));
+ }
+}
+
+/* informs user about connected status. private_ctx is used by user to identify
+ connection (multiple connections WIP) */
+int MemifConnector::onConnect(memif_conn_handle_t conn, void *private_ctx) {
+ TRANSPORT_LOGI("memif connected!\n");
+ MemifConnector *connector = (MemifConnector *)private_ctx;
+ memif_refill_queue(conn, 0, -1, 0);
+ connector->is_connecting_ = false;
+
+ return 0;
+}
+
+/* informs user about disconnected status. private_ctx is used by user to
+ identify connection (multiple connections WIP) */
+int MemifConnector::onDisconnect(memif_conn_handle_t conn, void *private_ctx) {
+ TRANSPORT_LOGI("memif disconnected!");
+ MemifConnector *connector = (MemifConnector *)private_ctx;
+ // TRANSPORT_LOGI ("Packet received: %u", connector->packet_counter_);
+ TRANSPORT_LOGI("Packet to process: %u",
+ connector->memif_connection_.tx_buf_num);
+ return 0;
+}
+
+void MemifConnector::threadMain() { event_reactor_.runEventLoop(1); }
+
+int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
+ uint16_t qid) {
+ MemifConnector *connector = (MemifConnector *)private_ctx;
+
+ memif_connection_t *c = &connector->memif_connection_;
+ int err = MEMIF_ERR_SUCCESS, ret_val;
+ uint16_t rx;
+
+ do {
+ err = memif_rx_burst(conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
+ ret_val = err;
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS &&
+ err != MEMIF_ERR_NOBUF)) {
+ TRANSPORT_LOGI("memif_rx_burst: %s", memif_strerror(err));
+ goto error;
+ }
+
+ c->rx_buf_num += rx;
+
+ if (TRANSPORT_EXPECT_TRUE(connector->io_service_.stopped())) {
+ TRANSPORT_LOGD("socket stopped: ignoring %u packets", rx);
+ goto error;
+ }
+
+ for (int i = 0; i < rx; i++) {
+ auto packet = connector->getPacket();
+ std::memcpy(packet->writableData(),
+ reinterpret_cast<const uint8_t *>((c->rx_bufs + i)->data),
+ (c->rx_bufs + i)->len);
+
+ if (!connector->input_buffer_.push(std::move(packet))) {
+ TRANSPORT_LOGI("Error pushing packet. Ring buffer full.");
+
+ // TODO Here we should consider the possibility to signal the congestion
+ // to the application, that would react properly (e.g. slow down
+ // message)
+ }
+ }
+
+ connector->io_service_.post(
+ std::bind(&MemifConnector::processInputBuffer, connector));
+
+ /* mark memif buffers and shared memory buffers as free */
+ /* free processed buffers */
+
+ err = memif_refill_queue(conn, qid, rx, 0);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err));
+ }
+
+ c->rx_buf_num -= rx;
+
+ TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx, rx,
+ MAX_MEMIF_BUFS - rx);
+
+ // if (connector->enable_burst_) {
+ // connector->doSend();
+ // }
+ } while (ret_val == MEMIF_ERR_NOBUF);
+
+ return 0;
+
+error:
+ err = memif_refill_queue(c->conn, qid, rx, 0);
+
+ if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+ TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err));
+ }
+ c->rx_buf_num -= rx;
+
+ TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx,
+ c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
+ return 0;
+}
+
+// void MemifConnector::runEventsLoop() {
+// io_service_.run();
+//}
+
+void MemifConnector::close() {
+ event_reactor_.stop();
+ io_service_.stop();
+
+ if (memif_worker_ && memif_worker_->joinable()) {
+ memif_worker_->join();
+ TRANSPORT_LOGD("Memif worker joined");
+ deleteMemif();
+ } else {
+ TRANSPORT_LOGD("Memif worker not joined");
+ }
+}
+
+void MemifConnector::enableBurst() { enable_burst_ = true; }
+
+void MemifConnector::send(const Packet::MemBufPtr &packet) {
+#ifdef CANCEL_TIMER
+ if (!timer_set_) {
+ timer_set_ = true;
+ send_timer_->expiresFromNow(std::chrono::microseconds(50));
+ send_timer_->asyncWait(
+ std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1));
+ }
+#endif
+
+ {
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+ output_buffer_.push_back(packet);
+ }
+}
+
+int MemifConnector::doSend() {
+ std::size_t max = 0;
+ uint16_t n = 0;
+ std::size_t size = 0;
+
+ {
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+ size = output_buffer_.size();
+ }
+
+ do {
+ max = size < MAX_MEMIF_BUFS ? size : MAX_MEMIF_BUFS;
+
+ if (TRANSPORT_EXPECT_FALSE(
+ (n = bufferAlloc(max, memif_connection_.tx_qid)) < 0)) {
+ TRANSPORT_LOGI("Error allocating buffers.");
+ return -1;
+ }
+
+ for (uint16_t i = 0; i < n; i++) {
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+
+ auto packet = output_buffer_.front().get();
+ const utils::MemBuf *current = packet;
+ std::size_t offset = 0;
+ uint8_t *shared_buffer =
+ reinterpret_cast<uint8_t *>(memif_connection_.tx_bufs[i].data);
+ do {
+ std::memcpy(shared_buffer + offset, current->data(), current->length());
+ offset += current->length();
+ current = current->next();
+ } while (current != packet);
+
+ memif_connection_.tx_bufs[i].len = uint32_t(offset);
+
+ TRANSPORT_LOGD("Packet size : %zu", offset);
+
+ output_buffer_.pop_front();
+ }
+
+ txBurst(memif_connection_.tx_qid);
+
+ utils::SpinLock::Acquire locked(write_msgs_lock_);
+ size = output_buffer_.size();
+ } while (size > 0);
+
+ return 0;
+}
+
+void MemifConnector::state() {
+ TRANSPORT_LOGD("Event reactor map: %zu", event_reactor_.mapSize());
+ TRANSPORT_LOGD("Output buffer %zu", output_buffer_.size());
+}
+
+void MemifConnector::send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent) {}
+
+} // end namespace core
+
+} // end namespace transport
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_connector.h b/libtransport/src/hicn/transport/core/memif_connector.h
new file mode 100755
index 000000000..24c8ac16c
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/memif_connector.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/fd_deadline_timer.h>
+#include <hicn/transport/utils/ring_buffer.h>
+
+#include <asio.hpp>
+#include <deque>
+#include <mutex>
+#include <thread>
+
+#ifdef __vpp__
+
+#define _Static_assert static_assert
+
+extern "C" {
+#include <memif/libmemif.h>
+};
+
+namespace transport {
+
+namespace core {
+
+typedef struct {
+ uint16_t index;
+ /* memif conenction handle */
+ memif_conn_handle_t conn;
+ /* transmit queue id */
+ uint16_t tx_qid;
+ /* tx buffers */
+ memif_buffer_t *tx_bufs;
+ /* allocated tx buffers counter */
+ /* number of tx buffers pointing to shared memory */
+ uint16_t tx_buf_num;
+ /* rx buffers */
+ memif_buffer_t *rx_bufs;
+ /* allcoated rx buffers counter */
+ /* number of rx buffers pointing to shared memory */
+ uint16_t rx_buf_num;
+ /* interface ip address */
+ uint8_t ip_addr[4];
+} memif_connection_t;
+
+#define APP_NAME "libtransport"
+#define IF_NAME "vpp_connection"
+
+#define MAX_MEMIF_BUFS 1024
+#define MEMIF_BUF_SIZE 2048
+#define MEMIF_LOG2_RING_SIZE 11
+
+class MemifConnector : public Connector {
+ public:
+ MemifConnector(PacketReceivedCallback &&receive_callback,
+ OnReconnect &&on_reconnect_callback,
+ asio::io_service &io_service,
+ std::string app_name = "Libtransport");
+
+ ~MemifConnector() override;
+
+ void send(const Packet::MemBufPtr &packet) override;
+
+ void send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent = 0) override;
+
+ void close() override;
+
+ void connect(uint32_t memif_id, long memif_mode);
+
+ // void runEventsLoop();
+
+ void enableBurst() override;
+
+ void state() override;
+
+ TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; };
+
+ private:
+ void init();
+
+ int doSend();
+
+ int createMemif(uint32_t index, uint8_t mode, char *s);
+
+ uint32_t getMemifConfiguration();
+
+ int deleteMemif();
+
+ static int controlFdUpdate(int fd, uint8_t events);
+
+ static int onConnect(memif_conn_handle_t conn, void *private_ctx);
+
+ static int onDisconnect(memif_conn_handle_t conn, void *private_ctx);
+
+ static int onInterrupt(memif_conn_handle_t conn, void *private_ctx,
+ uint16_t qid);
+
+ void threadMain();
+
+ int txBurst(uint16_t qid);
+
+ int bufferAlloc(long n, uint16_t qid);
+
+ void sendCallback(const std::error_code &ec);
+
+ void processInputBuffer();
+
+ private:
+ static utils::EpollEventReactor main_event_reactor_;
+ static std::unique_ptr<std::thread> main_worker_;
+
+ int epfd;
+ std::unique_ptr<std::thread> memif_worker_;
+ utils::EpollEventReactor event_reactor_;
+ volatile bool timer_set_;
+ std::unique_ptr<utils::FdDeadlineTimer> send_timer_;
+ asio::io_service &io_service_;
+ std::unique_ptr<asio::io_service::work> work_;
+ uint32_t packet_counter_;
+ memif_connection_t memif_connection_;
+ uint16_t tx_buf_counter_;
+
+ PacketRing input_buffer_;
+ volatile bool is_connecting_;
+ volatile bool is_reconnection_;
+ bool data_available_;
+ bool enable_burst_;
+ uint32_t memif_id_;
+ uint8_t memif_mode_;
+ std::string app_name_;
+ uint16_t transmission_index_;
+ PacketReceivedCallback receive_callback_;
+ OnReconnect on_reconnect_callback_;
+ utils::SpinLock write_msgs_lock_;
+ std::string socket_filename_;
+
+ static std::once_flag flag_;
+};
+
+} // end namespace core
+
+} // end namespace transport
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/name.cc b/libtransport/src/hicn/transport/core/name.cc
new file mode 100755
index 000000000..10c45eb08
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/name.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/errors/tokenizer_exception.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+namespace transport {
+
+namespace core {
+
+Name::Name() { name_ = createEmptyName(); }
+
+Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix)
+ : name_(createEmptyName()) {
+ std::size_t length;
+ uint8_t *dst = NULL;
+
+ if (family == AF_INET) {
+ dst = name_->ip4.prefix_as_u8;
+ length = IPV4_ADDR_LEN;
+ name_->type = HNT_CONTIGUOUS_V4;
+ } else if (family == AF_INET6) {
+ dst = name_->ip6.prefix_as_u8;
+ length = IPV6_ADDR_LEN;
+ name_->type = HNT_CONTIGUOUS_V6;
+ } else {
+ throw errors::RuntimeException("Specified name family does not exist.");
+ }
+
+ std::memcpy(dst, ip_address, length);
+ *reinterpret_cast<std::uint32_t *>(dst + length) = suffix;
+}
+
+Name::Name(const char *name, uint32_t segment) {
+ name_ = createEmptyName();
+
+ if (hicn_name_create(name, segment, name_.get()) < 0) {
+ throw errors::InvalidIpAddressException();
+ }
+}
+
+Name::Name(const std::string &uri, uint32_t segment)
+ : Name(uri.c_str(), segment) {}
+
+Name::Name(const std::string &uri) {
+ utils::StringTokenizer tokenizer(uri, "|");
+ std::string ip_address;
+ std::string seq_number;
+
+ ip_address = tokenizer.nextToken();
+
+ try {
+ seq_number = tokenizer.nextToken();
+ } catch (errors::TokenizerException &e) {
+ seq_number = "0";
+ }
+
+ name_ = createEmptyName();
+
+ if (hicn_name_create(ip_address.c_str(), (uint32_t)atoi(seq_number.c_str()),
+ name_.get()) < 0) {
+ throw errors::InvalidIpAddressException();
+ }
+}
+
+Name::Name(const Name &name, bool hard_copy) {
+ name_ = createEmptyName();
+
+ if (hard_copy) {
+ if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) {
+ throw errors::MalformedNameException();
+ }
+ } else {
+ *this->name_ = *name.name_;
+ }
+}
+
+Name::Name(Name &&name) : name_(std::move(name.name_)) {}
+
+Name &Name::operator=(const Name &name) {
+ if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) {
+ throw errors::MalformedNameException();
+ }
+
+ return *this;
+}
+
+bool Name::operator==(const Name &name) const {
+ return this->equals(name, true);
+}
+
+bool Name::operator!=(const Name &name) const {
+ return !this->operator==(name);
+}
+
+Name::operator bool() const {
+ return bool(hicn_name_empty((hicn_name_t *)name_.get()));
+}
+
+bool Name::equals(const Name &name, bool consider_segment) const {
+ return !hicn_name_compare(name_.get(), name.name_.get(), consider_segment);
+}
+
+std::string Name::toString() const {
+ char *name = new char[100];
+ int ret = hicn_name_ntop(name_.get(), name, standard_name_string_length);
+ if (ret < 0) {
+ throw errors::MalformedNameException();
+ }
+ std::string name_string(name);
+ delete[] name;
+
+ return name_string;
+}
+
+uint32_t Name::getHash32() const {
+ uint32_t hash;
+ if (hicn_name_hash((hicn_name_t *)name_.get(), &hash) < 0) {
+ throw errors::RuntimeException("Error computing the hash of the name!");
+ }
+ return hash;
+}
+
+void Name::clear() {
+ name_.reset();
+ name_ = createEmptyName();
+};
+
+Name::Type Name::getType() const { return name_->type; }
+
+uint32_t Name::getSuffix() const {
+ uint32_t ret = 0;
+ if (hicn_name_get_seq_number((hicn_name_t *)name_.get(), &ret) < 0) {
+ throw errors::RuntimeException(
+ "Impossible to retrieve the sequence number from the name.");
+ }
+ return ret;
+}
+
+Name &Name::setSuffix(uint32_t seq_number) {
+ if (hicn_name_set_seq_number(name_.get(), seq_number) < 0) {
+ throw errors::RuntimeException(
+ "Impossible to set the sequence number to the name.");
+ }
+
+ return *this;
+}
+
+std::shared_ptr<Sockaddr> Name::getAddress() const {
+ Sockaddr *ret = nullptr;
+
+ switch (name_->type) {
+ case HNT_CONTIGUOUS_V4:
+ case HNT_IOV_V4:
+ ret = (Sockaddr *)new Sockaddr4;
+ break;
+ case HNT_CONTIGUOUS_V6:
+ case HNT_IOV_V6:
+ ret = (Sockaddr *)new Sockaddr6;
+ break;
+ default:
+ throw errors::MalformedNameException();
+ }
+
+ if (hicn_name_to_sockaddr_address((hicn_name_t *)name_.get(), ret) < 0) {
+ throw errors::MalformedNameException();
+ }
+
+ return std::shared_ptr<Sockaddr>(ret);
+}
+
+ip_address_t Name::toIpAddress() const {
+ ip_address_t ret;
+ std::memset(&ret, 0, sizeof(ret));
+
+ if (hicn_name_to_ip_address(name_.get(), &ret) < 0) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ return ret;
+}
+
+int Name::getAddressFamily() const {
+ int ret = 0;
+
+ if (hicn_name_get_family(name_.get(), &ret) < 0) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ return ret;
+}
+
+void Name::copyToDestination(uint8_t *destination, bool include_suffix) const {
+ if (hicn_name_copy_to_destination(destination, name_.get(), include_suffix) <
+ 0) {
+ throw errors::RuntimeException(
+ "Impossibe to copy the name into the "
+ "provided destination");
+ }
+}
+
+std::ostream &operator<<(std::ostream &os, const Name &name) {
+ const std::string &str = name.toString();
+ // os << "core:/";
+ os << str;
+
+ return os;
+}
+
+} // end namespace core
+
+} // end namespace transport
+
+namespace std {
+size_t hash<transport::core::Name>::operator()(
+ const transport::core::Name &name) const {
+ return name.getHash32();
+}
+
+} // end namespace std
diff --git a/libtransport/src/hicn/transport/core/name.h b/libtransport/src/hicn/transport/core/name.h
new file mode 100755
index 000000000..b0da15026
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/name.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <list>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+};
+
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+typedef struct sockaddr_in6 Sockaddr6;
+typedef struct sockaddr_in Sockaddr4;
+typedef struct sockaddr Sockaddr;
+
+enum class HashAlgorithm : uint8_t;
+
+class Name {
+ friend class Packet;
+ friend class ContentObject;
+ friend class Interest;
+
+ static const uint32_t standard_name_string_length = 100;
+
+ public:
+ using NameStruct = hicn_name_t;
+ using Type = hicn_name_type_t;
+
+ Name();
+
+ /**
+ * @brief Create name
+ * @param name The null-terminated URI string
+ */
+ Name(const char *name, uint32_t segment);
+
+ Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0);
+
+ Name(const std::string &uri, uint32_t segment);
+
+ Name(const std::string &uri);
+
+ Name(const Name &name, bool hard_copy = false);
+
+ Name(Name &&name);
+
+ Name &operator=(const Name &name);
+
+ bool operator==(const Name &name) const;
+
+ bool operator!=(const Name &name) const;
+
+ operator bool() const;
+
+ std::string toString() const;
+
+ bool equals(const Name &name, bool consider_segment = true) const;
+
+ uint32_t getHash32() const;
+
+ void clear();
+
+ Type getType() const;
+
+ uint32_t getSuffix() const;
+
+ std::shared_ptr<Sockaddr> getAddress() const;
+
+ Name &setSuffix(uint32_t seq_number);
+
+ ip_address_t toIpAddress() const;
+
+ void copyToDestination(uint8_t *destination,
+ bool include_suffix = false) const;
+
+ int getAddressFamily() const;
+
+ private:
+ TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() const {
+ if (TRANSPORT_EXPECT_TRUE(name_ != nullptr)) {
+ return name_.get();
+ }
+
+ return nullptr;
+ }
+
+ static TRANSPORT_ALWAYS_INLINE std::unique_ptr<NameStruct> createEmptyName() {
+ NameStruct *name = new NameStruct;
+ name->type = HNT_UNSPEC;
+ return std::unique_ptr<NameStruct>(name);
+ };
+
+ std::unique_ptr<NameStruct> name_;
+};
+
+std::ostream &operator<<(std::ostream &os, const Name &name);
+
+} // end namespace core
+
+} // end namespace transport
+
+namespace std {
+template <>
+struct hash<transport::core::Name> {
+ size_t operator()(const transport::core::Name &name) const;
+};
+
+} // end namespace std
diff --git a/libtransport/src/hicn/transport/core/packet.cc b/libtransport/src/hicn/transport/core/packet.cc
new file mode 100755
index 000000000..74f407ff7
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/packet.cc
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/malformed_packet_exception.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/log.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/error.h>
+}
+
+namespace transport {
+
+namespace core {
+
+const core::Name Packet::base_name("0::0|0");
+
+Packet::Packet(Format format)
+ : packet_(utils::MemBuf::create(getHeaderSizeFromFormat(format)).release()),
+ packet_start_(packet_->writableData()),
+ header_head_(packet_.get()),
+ payload_head_(nullptr),
+ format_(format) {
+ if (hicn_packet_init_header(format, (hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Unexpected error initializing the packet.");
+ }
+
+ packet_->append(getHeaderSizeFromFormat(format_));
+}
+
+Packet::Packet(MemBufPtr &&buffer)
+ : packet_(std::move(buffer)),
+ packet_start_(packet_->writableData()),
+ header_head_(packet_.get()),
+ payload_head_(nullptr),
+ format_(getFormatFromBuffer(packet_start_)) {
+
+ auto header_size = getHeaderSizeFromFormat(format_);
+ int signature_size = 0;
+
+ if (_is_ah(format_)) {
+ signature_size = getSignatureSize();
+ }
+
+ auto payload_length = packet_->length() - header_size - signature_size;
+
+ if (!payload_length && !signature_size) {
+ return;
+ }
+
+ packet_->trimEnd(packet_->length());
+
+ if (signature_size) {
+ auto sig = packet_->cloneOne();
+ sig->advance(header_size);
+ sig->append(signature_size);
+ packet_->appendChain(std::move(sig));
+ }
+
+ if (payload_length) {
+ auto payload = packet_->cloneOne();
+ payload_head_ = payload.get();
+ payload_head_->advance(header_size + signature_size);
+ payload_head_->append(payload_length);
+ packet_->prependChain(std::move(payload));
+ packet_->append(header_size);
+ }
+
+
+}
+
+Packet::Packet(const uint8_t *buffer, std::size_t size)
+ : Packet(MemBufPtr(utils::MemBuf::copyBuffer(buffer, size).release())) {}
+
+Packet::Packet(Packet &&other)
+ : packet_(std::move(other.packet_)),
+ packet_start_(packet_->writableData()),
+ header_head_(other.header_head_),
+ payload_head_(other.payload_head_),
+ format_(other.format_) {
+ other.packet_start_ = nullptr;
+ other.header_head_ = nullptr;
+ other.payload_head_ = nullptr;
+ other.format_ = HF_UNSPEC;
+}
+
+Packet::~Packet() {
+ if (packet_->isChained()) {
+ packet_->separateChain(packet_->next(), packet_->prev());
+ }
+}
+
+std::size_t Packet::getHeaderSizeFromFormat(Format format,
+ size_t signature_size) {
+ std::size_t header_length;
+ hicn_packet_get_header_length_from_format(format, &header_length);
+ int is_ah = _is_ah(format);
+ return is_ah * (header_length + signature_size) + (!is_ah) * header_length;
+}
+
+std::size_t Packet::getHeaderSizeFromBuffer(Format format,
+ const uint8_t *buffer) {
+ size_t header_length;
+ if (hicn_packet_get_header_length(format, (hicn_header_t *)buffer,
+ &header_length) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ return header_length;
+}
+
+bool Packet::isInterest(const uint8_t *buffer) {
+ bool is_interest = false;
+
+ if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece((const hicn_header_t *)buffer,
+ &is_interest) < 0)) {
+ throw errors::RuntimeException(
+ "Impossible to retrieve ece flag from packet");
+ }
+
+ return !is_interest;
+}
+
+Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer) {
+ Format format = HF_UNSPEC;
+
+ if (TRANSPORT_EXPECT_FALSE(
+ hicn_packet_get_format((const hicn_header_t *)buffer, &format) < 0)) {
+ throw errors::MalformedPacketException();
+ }
+
+ return format;
+}
+
+std::size_t Packet::getPayloadSizeFromBuffer(Format format,
+ const uint8_t *buffer) {
+ std::size_t payload_length;
+ if (TRANSPORT_EXPECT_FALSE(
+ hicn_packet_get_payload_length(format, (hicn_header_t *)buffer,
+ &payload_length) < 0)) {
+ throw errors::MalformedPacketException();
+ }
+
+ return payload_length;
+}
+
+std::size_t Packet::payloadSize() const {
+ return getPayloadSizeFromBuffer(format_, packet_start_);
+}
+
+std::size_t Packet::headerSize() const {
+ return getHeaderSizeFromBuffer(format_, packet_start_);
+}
+
+const uint8_t *Packet::start() const { return packet_start_; }
+
+void Packet::setLifetime(uint32_t lifetime) {
+ if (hicn_interest_set_lifetime((hicn_header_t *)packet_start_, lifetime) <
+ 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+uint32_t Packet::getLifetime() const {
+ uint32_t lifetime = 0;
+
+ if (hicn_packet_get_lifetime((hicn_header_t *)packet_start_, &lifetime) < 0) {
+ throw errors::MalformedPacketException();
+ }
+
+ return lifetime;
+}
+
+Packet &Packet::appendPayload(std::unique_ptr<utils::MemBuf> &&payload) {
+ if (!payload_head_) {
+ payload_head_ = payload.get();
+ }
+
+ header_head_->prependChain(std::move(payload));
+ updateLength();
+ return *this;
+}
+
+Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) {
+ return appendPayload(utils::MemBuf::copyBuffer(buffer, length));
+}
+
+Packet &Packet::appendHeader(std::unique_ptr<utils::MemBuf> &&header) {
+ if (!payload_head_) {
+ header_head_->prependChain(std::move(header));
+ } else {
+ payload_head_->prependChain(std::move(header));
+ }
+
+ updateLength();
+ return *this;
+}
+
+Packet &Packet::appendHeader(const uint8_t *buffer, std::size_t length) {
+ return appendHeader(utils::MemBuf::copyBuffer(buffer, length));
+}
+
+utils::Array<uint8_t> Packet::getPayload() const {
+ if (TRANSPORT_EXPECT_FALSE(payload_head_ == nullptr)) {
+ return utils::Array<uint8_t>();
+ }
+
+ // Hopefully the payload is contiguous
+ if (TRANSPORT_EXPECT_FALSE(payload_head_->next() != header_head_)) {
+ payload_head_->gather(payloadSize());
+ }
+
+ return utils::Array<uint8_t>(payload_head_->writableData(),
+ payload_head_->length());
+}
+
+Packet &Packet::updateLength(std::size_t length) {
+ std::size_t total_length = length;
+
+ for (utils::MemBuf *current = payload_head_;
+ current && current != header_head_; current = current->next()) {
+ total_length += current->length();
+ }
+
+ if (hicn_packet_set_payload_length(format_, (hicn_header_t *)packet_start_,
+ total_length) < 0) {
+ throw errors::RuntimeException("Error setting the packet payload.");
+ }
+
+ return *this;
+}
+
+PayloadType Packet::getPayloadType() const {
+ hicn_payload_type_t ret = HPT_UNSPEC;
+
+ if (hicn_packet_get_payload_type((hicn_header_t *)packet_start_, &ret) < 0) {
+ throw errors::RuntimeException("Impossible to retrieve payload type.");
+ }
+
+ return PayloadType(ret);
+}
+
+Packet &Packet::setPayloadType(PayloadType payload_type) {
+ if (hicn_packet_set_payload_type((hicn_header_t *)packet_start_,
+ hicn_payload_type_t(payload_type)) < 0) {
+ throw errors::RuntimeException("Error setting payload type of the packet.");
+ }
+
+ return *this;
+}
+
+Packet::Format Packet::getFormat() const {
+ if (format_ == HF_UNSPEC) {
+ if (hicn_packet_get_format((hicn_header_t *)packet_start_, &format_) < 0) {
+ throw errors::MalformedPacketException();
+ }
+ }
+
+ return format_;
+}
+
+const std::shared_ptr<utils::MemBuf> Packet::data() { return packet_; }
+
+void Packet::dump() const {
+ TRANSPORT_LOGI("The header length is: %zu", headerSize());
+ TRANSPORT_LOGI("The payload length is: %zu", payloadSize());
+ std::cerr << std::endl;
+
+ hicn_packet_dump((uint8_t *)packet_->data(), headerSize());
+ // hicn_packet_dump((uint8_t *)packet_->next()->data(), payloadSize());
+}
+
+void Packet::setSignatureSize(std::size_t size_bytes) {
+ int ret = hicn_packet_set_signature_size(
+ format_, (hicn_header_t *)packet_start_, size_bytes);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+}
+
+std::size_t Packet::getSignatureSize() const {
+ size_t size_bytes;
+ int ret = hicn_packet_get_signature_size(
+ format_, (hicn_header_t *)packet_start_, &size_bytes);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ return size_bytes;
+}
+
+void Packet::setSignature(std::unique_ptr<utils::MemBuf> &&signature) {
+ // Check if packet already contains a signature
+ auto header = header_head_->next();
+ while (header != payload_head_) {
+ header->unlink();
+ header = header->next();
+ }
+
+ appendHeader(std::move(signature));
+}
+
+void Packet::setSignatureTimestamp(const uint64_t &timestamp) {
+ int ret = hicn_packet_set_signature_timestamp(
+ format_, (hicn_header_t *)packet_start_, timestamp);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting the signature timestamp.");
+ }
+}
+
+uint64_t Packet::getSignatureTimestamp() const {
+ uint64_t return_value;
+ int ret = hicn_packet_get_signature_timestamp(
+ format_, (hicn_header_t *)packet_start_, &return_value);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting the signature timestamp.");
+ }
+
+ return return_value;
+}
+
+void Packet::setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm) {
+ int ret = hicn_packet_set_validation_algorithm(
+ format_, (hicn_header_t *)packet_start_, uint8_t(validation_algorithm));
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting the validation algorithm.");
+ }
+}
+
+utils::CryptoSuite Packet::getValidationAlgorithm() const {
+ uint8_t return_value;
+ int ret = hicn_packet_get_validation_algorithm(
+ format_, (hicn_header_t *)packet_start_, &return_value);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting the validation algorithm.");
+ }
+
+ return utils::CryptoSuite(return_value);
+}
+
+void Packet::setKeyId(const utils::KeyId &key_id) {
+ int ret = hicn_packet_set_key_id(
+ format_, (hicn_header_t *)packet_start_, key_id.first);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting the key id.");
+ }
+}
+
+utils::KeyId Packet::getKeyId() const {
+ utils::KeyId return_value;
+ int ret = hicn_packet_get_key_id(
+ format_, (hicn_header_t *)packet_start_, &return_value.first, &return_value.second);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error getting the validation algorithm.");
+ }
+
+ return return_value;
+}
+
+utils::CryptoHash Packet::computeDigest(HashAlgorithm algorithm) const {
+ utils::CryptoHasher hasher(static_cast<utils::CryptoHashType>(algorithm));
+ hasher.init();
+
+ // Copy IP+TCP/ICMP header before zeroing them
+ hicn_header_t header_copy;
+
+ hicn_packet_copy_header(format_, (hicn_header_t *)packet_start_, &header_copy,
+ false);
+
+ const_cast<Packet *>(this)->resetForHash();
+
+ std::size_t payload_len = getPayloadSizeFromBuffer(format_, packet_start_);
+ std::size_t header_length = getHeaderSizeFromFormat(format_);
+ std::size_t signature_size = _is_ah(format_) ? getSignatureSize() : 0;
+
+ hasher.updateBytes(packet_start_,
+ payload_len + header_length + signature_size);
+
+ hicn_packet_copy_header(format_, &header_copy, (hicn_header_t *)packet_start_,
+ false);
+
+ return hasher.finalize();
+}
+
+void Packet::setChecksum() {
+ uint16_t partial_csum = 0;
+
+ for (utils::MemBuf *current = header_head_->next();
+ current && current != header_head_; current = current->next()) {
+ if (partial_csum != 0) {
+ partial_csum = ~partial_csum;
+ }
+ partial_csum = csum(current->data(), current->length(), partial_csum);
+ }
+ if (hicn_packet_compute_header_checksum(
+ format_, (hicn_header_t *)packet_start_, partial_csum) < 0) {
+ throw errors::MalformedPacketException();
+ }
+}
+
+bool Packet::checkIntegrity() const {
+ if (hicn_packet_check_integrity(format_, (hicn_header_t *)packet_start_) <
+ 0) {
+ return false;
+ }
+
+ return true;
+}
+
+Packet &Packet::setSyn() {
+ if (hicn_packet_set_syn((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error setting syn bit in the packet.");
+ }
+
+ return *this;
+}
+
+Packet &Packet::resetSyn() {
+ if (hicn_packet_reset_syn((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error resetting syn bit in the packet.");
+ }
+
+ return *this;
+}
+
+bool Packet::testSyn() const {
+ bool res = false;
+ if (hicn_packet_test_syn((hicn_header_t *)packet_start_, &res) < 0) {
+ throw errors::RuntimeException("Error testing syn bit in the packet.");
+ }
+
+ return res;
+}
+
+Packet &Packet::setAck() {
+ if (hicn_packet_set_ack((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error setting ack bit in the packet.");
+ }
+
+ return *this;
+}
+
+Packet &Packet::resetAck() {
+ if (hicn_packet_reset_ack((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error resetting ack bit in the packet.");
+ }
+
+ return *this;
+}
+
+bool Packet::testAck() const {
+ bool res = false;
+ if (hicn_packet_test_ack((hicn_header_t *)packet_start_, &res) < 0) {
+ throw errors::RuntimeException("Error testing ack bit in the packet.");
+ }
+
+ return res;
+}
+
+Packet &Packet::setRst() {
+ if (hicn_packet_set_rst((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error setting rst bit in the packet.");
+ }
+
+ return *this;
+}
+
+Packet &Packet::resetRst() {
+ if (hicn_packet_reset_rst((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error resetting rst bit in the packet.");
+ }
+
+ return *this;
+}
+
+bool Packet::testRst() const {
+ bool res = false;
+ if (hicn_packet_test_rst((hicn_header_t *)packet_start_, &res) < 0) {
+ throw errors::RuntimeException("Error testing rst bit in the packet.");
+ }
+
+ return res;
+}
+
+Packet &Packet::setFin() {
+ if (hicn_packet_set_fin((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error setting fin bit in the packet.");
+ }
+
+ return *this;
+}
+
+Packet &Packet::resetFin() {
+ if (hicn_packet_reset_fin((hicn_header_t *)packet_start_) < 0) {
+ throw errors::RuntimeException("Error resetting fin bit in the packet.");
+ }
+
+ return *this;
+}
+
+bool Packet::testFin() const {
+ bool res = false;
+ if (hicn_packet_test_fin((hicn_header_t *)packet_start_, &res) < 0) {
+ throw errors::RuntimeException("Error testing fin bit in the packet.");
+ }
+
+ return res;
+}
+
+Packet &Packet::resetFlags() {
+ resetSyn();
+ resetAck();
+ resetRst();
+ resetFin();
+
+ return *this;
+}
+
+std::string Packet::printFlags() const {
+ std::string flags = "";
+ if (testSyn()) {
+ flags += "S";
+ }
+ if (testAck()) {
+ flags += "A";
+ }
+ if (testRst()) {
+ flags += "R";
+ }
+ if (testFin()) {
+ flags += "F";
+ }
+ return flags;
+}
+
+Packet &Packet::setSrcPort(uint16_t srcPort) {
+ if (hicn_packet_set_src_port((hicn_header_t *)packet_start_, srcPort) < 0) {
+ throw errors::RuntimeException("Error setting source port in the packet.");
+ }
+
+ return *this;
+}
+
+Packet &Packet::setDstPort(uint16_t dstPort) {
+ if (hicn_packet_set_dst_port((hicn_header_t *)packet_start_, dstPort) < 0) {
+ throw errors::RuntimeException(
+ "Error setting destination port in the packet.");
+ }
+
+ return *this;
+}
+
+uint16_t Packet::getSrcPort() const {
+ uint16_t port = 0;
+
+ if (hicn_packet_get_src_port((hicn_header_t *)packet_start_, &port) < 0) {
+ throw errors::RuntimeException("Error reading source port in the packet.");
+ }
+
+ return port;
+}
+
+uint16_t Packet::getDstPort() const {
+ uint16_t port = 0;
+
+ if (hicn_packet_get_dst_port((hicn_header_t *)packet_start_, &port) < 0) {
+ throw errors::RuntimeException(
+ "Error reading destination port in the packet.");
+ }
+
+ return port;
+}
+
+Packet &Packet::setTTL(uint8_t hops) {
+ if (hicn_packet_set_hoplimit((hicn_header_t *)packet_start_, hops) < 0) {
+ throw errors::RuntimeException("Error setting TTL.");
+ }
+
+ return *this;
+}
+
+uint8_t Packet::getTTL() const {
+ uint8_t hops = 0;
+ if (hicn_packet_get_hoplimit((hicn_header_t *)packet_start_, &hops) < 0) {
+ throw errors::RuntimeException("Error reading TTL.");
+ }
+
+ return hops;
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h
new file mode 100755
index 000000000..0a5673401
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/packet.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/payload_type.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+#include <hicn/transport/utils/crypto_hasher.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/key_id.h>
+
+namespace utils {
+class Signer;
+class Verifier;
+} // namespace utils
+
+namespace transport {
+
+namespace core {
+
+/*
+ * Basic IP packet, modelled as circular chain of buffers:
+ * Header = H
+ * Payload = P
+ *
+ * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2
+ * \_______________________________________|
+ */
+
+class Packet : public std::enable_shared_from_this<Packet> {
+ friend class utils::Signer;
+ friend class utils::Verifier;
+
+ public:
+ using MemBufPtr = std::shared_ptr<utils::MemBuf>;
+ using Format = hicn_format_t;
+ static constexpr size_t default_mtu = 1500;
+
+ /**
+ * Create new IP packet. Here we allocate just the header,
+ * the eventual payload will be added by prepending the payload buffer
+ * to the buffer chain whose the fist buffer is the header itself.
+ */
+ Packet(Format format = HF_UNSPEC);
+
+ /**
+ * Create new IP packet using raw buffer.
+ */
+ Packet(const uint8_t *buffer, std::size_t size);
+ Packet(MemBufPtr &&buffer);
+
+ /*
+ * Enforce zero-copy lifestyle.
+ */
+ Packet(const Packet &other) = delete;
+ Packet &operator=(const Packet &other) = delete;
+
+ /*
+ * Move constructor.
+ */
+ Packet(Packet &&other);
+
+ friend bool operator==(const Packet &l_packet, const Packet &r_packet);
+
+ virtual ~Packet();
+
+ static std::size_t getHeaderSizeFromFormat(Format format,
+ std::size_t signature_size = 0);
+
+ static std::size_t getHeaderSizeFromBuffer(Format format,
+ const uint8_t *buffer);
+
+ static std::size_t getPayloadSizeFromBuffer(Format format,
+ const uint8_t *buffer);
+
+ static bool isInterest(const uint8_t *buffer);
+
+ static Format getFormatFromBuffer(const uint8_t *buffer);
+
+ std::size_t payloadSize() const;
+
+ std::size_t headerSize() const;
+
+ const std::shared_ptr<utils::MemBuf> data();
+
+ const uint8_t *start() const;
+
+ virtual void setLifetime(uint32_t lifetime);
+
+ virtual uint32_t getLifetime() const;
+
+ Packet &appendPayload(const uint8_t *buffer, std::size_t length);
+
+ Packet &appendPayload(std::unique_ptr<utils::MemBuf> &&payload);
+
+ Packet &appendHeader(std::unique_ptr<utils::MemBuf> &&header);
+
+ Packet &appendHeader(const uint8_t *buffer, std::size_t length);
+
+ utils::Array<uint8_t> getPayload() const;
+
+ Packet &updateLength(std::size_t length = 0);
+
+ PayloadType getPayloadType() const;
+
+ Packet &setPayloadType(PayloadType payload_type);
+
+ Format getFormat() const;
+
+ void dump() const;
+
+ virtual void setLocator(const ip_address_t &locator) = 0;
+
+ virtual ip_address_t getLocator() const = 0;
+
+ void setSignatureSize(std::size_t size_bytes);
+
+ std::size_t getSignatureSize() const;
+
+ void setSignatureTimestamp(const uint64_t &timestamp);
+
+ uint64_t getSignatureTimestamp() const;
+
+ void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm);
+
+ utils::CryptoSuite getValidationAlgorithm() const;
+
+ void setKeyId(const utils::KeyId &key_id);
+
+ utils::KeyId getKeyId() const;
+
+ void setSignature(std::unique_ptr<utils::MemBuf> &&signature);
+
+ virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const;
+
+ void setChecksum();
+
+ bool checkIntegrity() const;
+
+ Packet &setSyn();
+ Packet &resetSyn();
+ bool testSyn() const;
+ Packet &setAck();
+ Packet &resetAck();
+ bool testAck() const;
+ Packet &setRst();
+ Packet &resetRst();
+ bool testRst() const;
+ Packet &setFin();
+ Packet &resetFin();
+ bool testFin() const;
+ Packet &resetFlags();
+ std::string printFlags() const;
+
+ Packet &setSrcPort(uint16_t srcPort);
+ Packet &setDstPort(uint16_t dstPort);
+ uint16_t getSrcPort() const;
+ uint16_t getDstPort() const;
+
+ Packet &setTTL(uint8_t hops);
+ uint8_t getTTL() const;
+
+ private:
+ virtual void resetForHash() = 0;
+
+ protected:
+ Name name_;
+ MemBufPtr packet_;
+ uint8_t *packet_start_;
+ utils::MemBuf *header_head_;
+ utils::MemBuf *payload_head_;
+ mutable Format format_;
+
+ static const core::Name base_name;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/payload_type.h b/libtransport/src/hicn/transport/core/payload_type.h
new file mode 100755
index 000000000..fa79db35a
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/payload_type.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace core {
+
+enum class PayloadType : uint16_t {
+ CONTENT_OBJECT = HPT_DATA,
+ MANIFEST = HPT_MANIFEST,
+};
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/pending_interest.cc b/libtransport/src/hicn/transport/core/pending_interest.cc
new file mode 100755
index 000000000..8f6de1839
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/pending_interest.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/pending_interest.h>
+
+namespace transport {
+
+namespace core {
+
+PendingInterest::PendingInterest()
+ : interest_(nullptr, nullptr), timer_(), received_(false) {}
+
+PendingInterest::PendingInterest(Interest::Ptr &&interest,
+ std::unique_ptr<asio::steady_timer> &&timer)
+ : interest_(std::move(interest)),
+ timer_(std::move(timer)),
+ received_(false) {}
+
+PendingInterest::~PendingInterest() {
+ // timer_.reset();
+}
+
+void PendingInterest::cancelTimer() { timer_->cancel(); }
+
+bool PendingInterest::isReceived() const { return received_; }
+
+void PendingInterest::setReceived() { received_ = true; }
+
+Interest::Ptr &&PendingInterest::getInterest() { return std::move(interest_); }
+
+void PendingInterest::setReceived(bool received) {
+ PendingInterest::received_ = received;
+}
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/pending_interest.h b/libtransport/src/hicn/transport/core/pending_interest.h
new file mode 100755
index 000000000..cbcafb5d9
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/pending_interest.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/deadline_timer.h>
+
+#include <asio/steady_timer.hpp>
+
+namespace transport {
+
+namespace core {
+
+class HicnForwarderInterface;
+class VPPForwarderInterface;
+class RawSocketInterface;
+
+template <typename ForwarderInt>
+class Portal;
+
+typedef std::function<void(const std::error_code &)> TimerCallback;
+
+class PendingInterest {
+ friend class Portal<HicnForwarderInterface>;
+ friend class Portal<VPPForwarderInterface>;
+ friend class Portal<RawSocketInterface>;
+
+ public:
+ PendingInterest();
+
+ PendingInterest(Interest::Ptr &&interest,
+ std::unique_ptr<asio::steady_timer> &&timer);
+
+ ~PendingInterest();
+
+ bool isReceived() const;
+
+ template <typename Handler>
+ TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) {
+ timer_->expires_from_now(
+ std::chrono::milliseconds(interest_->getLifetime()));
+ timer_->async_wait(cb);
+ }
+
+ void cancelTimer();
+
+ void setReceived();
+
+ Interest::Ptr &&getInterest();
+
+ void setReceived(bool received);
+
+ bool isValid() const;
+
+ void setValid(bool valid);
+
+ private:
+ Interest::Ptr interest_;
+ std::unique_ptr<asio::steady_timer> timer_;
+ bool received_;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h
new file mode 100755
index 000000000..88020447f
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/portal.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/pending_interest.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#ifdef __vpp__
+#include <hicn/transport/core/memif_connector.h>
+#endif
+
+#include <asio.hpp>
+#include <asio/steady_timer.hpp>
+#include <future>
+#include <memory>
+#include <unordered_map>
+
+#define UNSET_CALLBACK 0
+
+namespace transport {
+
+namespace core {
+
+typedef std::unordered_map<Name, std::unique_ptr<PendingInterest>>
+ PendingInterestHashTable;
+
+template <typename PrefixType>
+class BasicBindConfig {
+ static_assert(std::is_same<Prefix, PrefixType>::value,
+ "Prefix must be a Prefix type.");
+
+ const uint32_t standard_cs_reserved = 5000;
+
+ public:
+ template <typename T>
+ BasicBindConfig(T &&prefix)
+ : prefix_(std::forward<T &&>(prefix)),
+ content_store_reserved_(standard_cs_reserved) {}
+
+ template <typename T>
+ BasicBindConfig(T &&prefix, uint32_t cs_reserved)
+ : prefix_(std::forward<T &&>(prefix)),
+ content_store_reserved_(cs_reserved) {}
+
+ TRANSPORT_ALWAYS_INLINE const PrefixType &prefix() const { return prefix_; }
+
+ TRANSPORT_ALWAYS_INLINE uint32_t csReserved() const {
+ return content_store_reserved_;
+ }
+
+ private:
+ PrefixType prefix_;
+ uint32_t content_store_reserved_;
+};
+
+using BindConfig = BasicBindConfig<Prefix>;
+
+template <typename ForwarderInt>
+class Portal {
+ static_assert(
+ std::is_base_of<ForwarderInterface<ForwarderInt,
+ typename ForwarderInt::ConnectorType>,
+ ForwarderInt>::value,
+ "ForwarderInt must inherit from ForwarderInterface!");
+
+ public:
+ class ConsumerCallback {
+ public:
+ virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0;
+ virtual void onTimeout(Interest::Ptr &&i) = 0;
+ };
+
+ class ProducerCallback {
+ public:
+ virtual void onInterest(Interest::Ptr &&i) = 0;
+ };
+
+ Portal() : Portal(internal_io_service_) {
+ internal_work_ = std::make_unique<asio::io_service::work>(io_service_);
+ }
+
+ Portal(asio::io_service &io_service)
+ : io_service_(io_service),
+ is_running_(false),
+ app_name_("libtransport_application"),
+ consumer_callback_(nullptr),
+ producer_callback_(nullptr),
+ connector_(std::bind(&Portal::processIncomingMessages, this,
+ std::placeholders::_1),
+ std::bind(&Portal::setLocalRoutes, this), io_service_,
+ app_name_),
+ forwarder_interface_(connector_) {}
+
+ void setConsumerCallback(ConsumerCallback *consumer_callback) {
+ consumer_callback_ = consumer_callback;
+ }
+
+ void setProducerCallback(ProducerCallback *producer_callback) {
+ producer_callback_ = producer_callback;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void setOutputInterface(
+ const std::string &output_interface) {
+ forwarder_interface_.setOutputInterface(output_interface);
+ }
+
+ TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) {
+ forwarder_interface_.connect(is_consumer);
+ }
+
+ ~Portal() {
+ connector_.close();
+ stopEventsLoop();
+ }
+
+ TRANSPORT_ALWAYS_INLINE bool interestIsPending(const Name &name) {
+ auto it = pending_interest_hash_table_.find(name);
+ if (it != pending_interest_hash_table_.end())
+ if (!it->second->isReceived()) return true;
+
+ return false;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void sendInterest(Interest::Ptr &&interest) {
+ const Name name(interest->getName(), true);
+
+ // Send it
+ forwarder_interface_.send(*interest);
+
+ pending_interest_hash_table_[name] = std::make_unique<PendingInterest>(
+ std::move(interest), std::make_unique<asio::steady_timer>(io_service_));
+
+ pending_interest_hash_table_[name]->startCountdown(
+ std::bind(&Portal<ForwarderInt>::timerHandler, this,
+ std::placeholders::_1, name));
+ }
+
+ TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec,
+ const Name &name) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ std::unordered_map<Name, std::unique_ptr<PendingInterest>>::iterator it =
+ pending_interest_hash_table_.find(name);
+ if (it != pending_interest_hash_table_.end()) {
+ std::unique_ptr<PendingInterest> ptr = std::move(it->second);
+ pending_interest_hash_table_.erase(it);
+
+ if (consumer_callback_) {
+ consumer_callback_->onTimeout(std::move(ptr->getInterest()));
+ }
+ }
+ }
+ }
+
+ TRANSPORT_ALWAYS_INLINE void bind(const BindConfig &config) {
+ connector_.enableBurst();
+ forwarder_interface_.setContentStoreSize(config.csReserved());
+ served_namespaces_.push_back(config.prefix());
+ registerRoute(served_namespaces_.back());
+ }
+
+ TRANSPORT_ALWAYS_INLINE void runEventsLoop() {
+ if (io_service_.stopped()) {
+ io_service_.reset(); // ensure that run()/poll() will do some work
+ }
+
+ is_running_ = true;
+ this->io_service_.run();
+ is_running_ = false;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void runOneEvent() {
+ if (io_service_.stopped()) {
+ io_service_.reset(); // ensure that run()/poll() will do some work
+ }
+
+ is_running_ = true;
+ this->io_service_.run_one();
+ is_running_ = false;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void sendContentObject(
+ ContentObject &content_object) {
+ forwarder_interface_.send(content_object);
+ }
+
+ TRANSPORT_ALWAYS_INLINE void stopEventsLoop() {
+ is_running_ = false;
+ internal_work_.reset();
+
+ for (auto &pend_interest : pending_interest_hash_table_) {
+ pend_interest.second->cancelTimer();
+ }
+
+ clear();
+
+ io_service_.post([this]() { io_service_.stop(); });
+ }
+
+ TRANSPORT_ALWAYS_INLINE void killConnection() { connector_.close(); }
+
+ TRANSPORT_ALWAYS_INLINE void clear() { pending_interest_hash_table_.clear();}
+
+ TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() {
+ return io_service_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE std::size_t getPITSize() {
+ connector_.state();
+ return pending_interest_hash_table_.size();
+ }
+
+ TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) {
+ forwarder_interface_.registerRoute(prefix);
+ }
+
+ private:
+ TRANSPORT_ALWAYS_INLINE void processIncomingMessages(
+ Packet::MemBufPtr &&packet_buffer) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ if (packet_buffer->data()[0] == ForwarderInt::ack_code) {
+ // Hicn forwarder message
+ processControlMessage(std::move(packet_buffer));
+ return;
+ }
+
+ bool is_interest = Packet::isInterest(packet_buffer->data());
+ Packet::Format format = Packet::getFormatFromBuffer(packet_buffer->data());
+
+ if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) {
+ if (!is_interest) {
+ processContentObject(
+ ContentObject::Ptr(new ContentObject(std::move(packet_buffer))));
+ } else {
+ processInterest(Interest::Ptr(new Interest(std::move(packet_buffer))));
+ }
+ } else {
+ TRANSPORT_LOGE("Received not supported packet. Ignoring it.");
+ }
+ }
+
+ TRANSPORT_ALWAYS_INLINE void setLocalRoutes() {
+ for (auto &name : served_namespaces_) {
+ registerRoute(name);
+ }
+ }
+
+ TRANSPORT_ALWAYS_INLINE void processInterest(Interest::Ptr &&interest) {
+ // Interest for a producer
+ if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) {
+ producer_callback_->onInterest(std::move(interest));
+ }
+ }
+
+ TRANSPORT_ALWAYS_INLINE void processContentObject(
+ ContentObject::Ptr &&content_object) {
+ PendingInterestHashTable::iterator it =
+ pending_interest_hash_table_.find(content_object->getName());
+
+ if (TRANSPORT_EXPECT_TRUE(it != pending_interest_hash_table_.end())) {
+ std::unique_ptr<PendingInterest> interest_ptr = std::move(it->second);
+ interest_ptr->cancelTimer();
+
+ if (TRANSPORT_EXPECT_TRUE(!interest_ptr->isReceived())) {
+ interest_ptr->setReceived();
+ pending_interest_hash_table_.erase(content_object->getName());
+
+ if (consumer_callback_) {
+ consumer_callback_->onContentObject(
+ std::move(interest_ptr->getInterest()),
+ std::move(content_object));
+ }
+
+ } else {
+ TRANSPORT_LOGW(
+ "Content already received (interest already satisfied).");
+ }
+ } else {
+ TRANSPORT_LOGW("No pending interests for current content (%s)",
+ content_object->getName().toString().c_str());
+ }
+ }
+
+ TRANSPORT_ALWAYS_INLINE void processControlMessage(
+ Packet::MemBufPtr &&packet_buffer) {
+ // Control message as response to the route set by a producer.
+ // Do nothing
+ }
+
+ private:
+ asio::io_service &io_service_;
+ asio::io_service internal_io_service_;
+ std::unique_ptr<asio::io_service::work> internal_work_;
+
+ volatile bool is_running_;
+
+ std::string app_name_;
+
+ PendingInterestHashTable pending_interest_hash_table_;
+
+ ConsumerCallback *consumer_callback_;
+ ProducerCallback *producer_callback_;
+
+ typename ForwarderInt::ConnectorType connector_;
+ ForwarderInt forwarder_interface_;
+
+ std::list<Prefix> served_namespaces_;
+
+ ip_address_t locator4_;
+ ip_address_t locator6_;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/prefix.cc b/libtransport/src/hicn/transport/core/prefix.cc
new file mode 100755
index 000000000..69c2b845a
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/prefix.cc
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/prefix.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+extern "C" {
+#include <arpa/inet.h>
+}
+
+#include <cstring>
+#include <memory>
+#include <random>
+
+namespace transport {
+
+namespace core {
+
+Prefix::Prefix() { std::memset(&ip_address_, 0, sizeof(ip_address_t)); }
+
+Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {}
+
+Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {}
+
+Prefix::Prefix(const std::string &prefix) {
+ utils::StringTokenizer st(prefix, "/");
+
+ std::string ip_address = st.nextToken();
+ int family = get_addr_family(ip_address.c_str());
+
+ std::string prefix_length = family == AF_INET6 ? "128" : "32";
+
+ if (st.hasMoreTokens()) {
+ prefix_length = st.nextToken();
+ }
+
+ buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family);
+}
+
+Prefix::Prefix(std::string &prefix, uint16_t prefix_length) {
+ int family = get_addr_family(prefix.c_str());
+ buildPrefix(prefix, prefix_length, family);
+}
+
+Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) {
+ int family = content_name.getAddressFamily();
+
+ if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ ip_address_ = content_name.toIpAddress();
+ ip_address_.prefix_len = prefix_length;
+ ip_address_.family = family;
+}
+
+void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length,
+ int family) {
+ if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ int ret = inet_pton(family, prefix.c_str(), ip_address_.buffer);
+
+ if (ret != 1) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ ip_address_.prefix_len = prefix_length;
+ ip_address_.family = family;
+}
+
+std::unique_ptr<Sockaddr> Prefix::toSockaddr() {
+ Sockaddr *ret = nullptr;
+
+ switch (ip_address_.family) {
+ case AF_INET6:
+ ret = (Sockaddr *)new Sockaddr6;
+ break;
+ case AF_INET:
+ ret = (Sockaddr *)new Sockaddr4;
+ break;
+ default:
+ throw errors::InvalidIpAddressException();
+ }
+
+ if (hicn_ip_to_sockaddr_address(&ip_address_, ret) < 0) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ return std::unique_ptr<Sockaddr>(ret);
+}
+
+uint16_t Prefix::getPrefixLength() { return ip_address_.prefix_len; }
+
+Prefix &Prefix::setPrefixLength(uint16_t prefix_length) {
+ ip_address_.prefix_len = prefix_length;
+ return *this;
+}
+
+int Prefix::getAddressFamily() { return ip_address_.family; }
+
+Prefix &Prefix::setAddressFamily(int address_family) {
+ ip_address_.family = address_family;
+ return *this;
+}
+
+std::string Prefix::getNetwork() const {
+ if (!checkPrefixLengthAndAddressFamily(ip_address_.prefix_len,
+ ip_address_.family)) {
+ throw errors::InvalidIpAddressException();
+ }
+
+ std::size_t size =
+ ip_address_.family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+
+ std::string network(size, 0);
+
+ if (hicn_ip_ntop(&ip_address_, (char *)network.c_str(), size) < 0) {
+ throw errors::RuntimeException(
+ "Impossible to retrieve network from ip address.");
+ }
+
+ return network;
+}
+
+Name Prefix::getName() const {
+ std::string s(getNetwork());
+ return Name(s);
+}
+
+Prefix &Prefix::setNetwork(std::string &network) {
+ if (!inet_pton(AF_INET6, network.c_str(), ip_address_.buffer)) {
+ throw errors::RuntimeException("The network name is not valid.");
+ }
+
+ return *this;
+}
+
+Name Prefix::makeRandomName() const {
+ srand(time(nullptr));
+
+ if (ip_address_.family == AF_INET6) {
+ std::default_random_engine eng((std::random_device())());
+ std::uniform_int_distribution<uint32_t> idis(
+ 0, std::numeric_limits<uint32_t>::max());
+ uint64_t random_number = idis(eng);
+
+ uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_address_.prefix_len;
+ uint64_t ip_address[2];
+ memcpy(ip_address, ip_address_.buffer, sizeof(uint64_t));
+ memcpy(ip_address + 1, ip_address_.buffer + 8, sizeof(uint64_t));
+ std::string network(IPV6_ADDR_LEN * 3, 0);
+
+ // Let's do the magic ;)
+ int shift_size = hash_size_bits > sizeof(random_number) * 8
+ ? sizeof(random_number) * 8
+ : hash_size_bits;
+
+ ip_address[1] >>= shift_size;
+ ip_address[1] <<= shift_size;
+
+ ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size);
+
+ if (!inet_ntop(ip_address_.family, ip_address, (char *)network.c_str(),
+ IPV6_ADDR_LEN * 3)) {
+ throw errors::RuntimeException(
+ "Impossible to retrieve network from ip address.");
+ }
+
+ return Name(network);
+ }
+
+ return Name();
+}
+
+bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
+ int family) {
+ // First check the family
+ if (family != AF_INET6 && family != AF_INET) {
+ return false;
+ }
+
+ int max_addr_len_bits =
+ family == AF_INET6 ? IPV6_ADDR_LEN_BITS : IPV4_ADDR_LEN_BITS;
+
+ if (prefix_length > max_addr_len_bits) {
+ return false;
+ }
+
+ return true;
+}
+
+ip_address_t &Prefix::toIpAddressStruct() { return ip_address_; }
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/prefix.h b/libtransport/src/hicn/transport/core/prefix.h
new file mode 100755
index 000000000..b68c6bdf6
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/prefix.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+namespace transport {
+
+namespace core {
+
+class Prefix {
+ public:
+ Prefix();
+
+ Prefix(const char *prefix);
+
+ Prefix(const std::string &prefix);
+
+ Prefix(std::string &&prefix);
+
+ Prefix(std::string &prefix, uint16_t prefix_length);
+
+ Prefix(const core::Name &content_name, uint16_t prefix_length);
+
+ std::unique_ptr<Sockaddr> toSockaddr();
+
+ uint16_t getPrefixLength();
+
+ Prefix &setPrefixLength(uint16_t prefix_length);
+
+ std::string getNetwork() const;
+
+ Name getName() const;
+
+ Prefix &setNetwork(std::string &network);
+
+ int getAddressFamily();
+
+ Prefix &setAddressFamily(int address_family);
+
+ Name makeRandomName() const;
+
+ ip_address_t &toIpAddressStruct();
+
+ private:
+ static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
+ int family);
+
+ void buildPrefix(std::string &prefix, uint16_t prefix_length, int family);
+
+ ip_address_t ip_address_;
+};
+
+} // end namespace core
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.cc b/libtransport/src/hicn/transport/core/raw_socket_connector.cc
new file mode 100755
index 000000000..5cfff39fb
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/raw_socket_connector.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/raw_socket_connector.h>
+#include <hicn/transport/utils/conversions.h>
+#include <hicn/transport/utils/log.h>
+
+#include <net/if.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#define MY_DEST_MAC0 0x0a
+#define MY_DEST_MAC1 0x7b
+#define MY_DEST_MAC2 0x7c
+#define MY_DEST_MAC3 0x1c
+#define MY_DEST_MAC4 0x4a
+#define MY_DEST_MAC5 0x14
+
+namespace transport {
+
+namespace core {
+
+RawSocketConnector::RawSocketConnector(
+ PacketReceivedCallback &&receive_callback,
+ OnReconnect &&on_reconnect_callback, asio::io_service &io_service,
+ std::string app_name)
+ : Connector(),
+ io_service_(io_service),
+ socket_(io_service_, raw_protocol(PF_PACKET, SOCK_RAW)),
+ // resolver_(io_service_),
+ timer_(io_service_),
+ read_msg_(packet_pool_.makePtr(nullptr)),
+ data_available_(false),
+ receive_callback_(receive_callback),
+ on_reconnect_callback_(on_reconnect_callback),
+ app_name_(app_name) {
+ memset(&link_layer_address_, 0, sizeof(link_layer_address_));
+}
+
+RawSocketConnector::~RawSocketConnector() {}
+
+void RawSocketConnector::connect(const std::string &interface_name,
+ const std::string &mac_address_str) {
+ memset(&ethernet_header_, 0, sizeof(ethernet_header_));
+ struct ifreq ifr;
+ struct ifreq if_mac;
+ uint8_t mac_address[6];
+
+ utils::convertStringToMacAddress(mac_address_str, mac_address);
+
+ // Get interface mac address
+ int fd = static_cast<int>(socket_.native_handle());
+
+ /* Get the index of the interface to send on */
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, interface_name.c_str(), interface_name.size());
+
+ // if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0) {
+ // perror("SIOCGIFINDEX");
+ // }
+
+ /* Get the MAC address of the interface to send on */
+ memset(&if_mac, 0, sizeof(struct ifreq));
+ strncpy(if_mac.ifr_name, interface_name.c_str(), interface_name.size());
+ if (ioctl(fd, SIOCGIFHWADDR, &if_mac) < 0) {
+ perror("SIOCGIFHWADDR");
+ throw errors::RuntimeException("Interface does not exist");
+ }
+
+ /* Ethernet header */
+ for (int i = 0; i < 6; i++) {
+ ethernet_header_.ether_shost[i] =
+ ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[i];
+ ethernet_header_.ether_dhost[i] = mac_address[i];
+ }
+
+ /* Ethertype field */
+ ethernet_header_.ether_type = htons(ETH_P_IPV6);
+
+ strcpy(ifr.ifr_name, interface_name.c_str());
+
+ if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) {
+ memcpy(link_layer_address_.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
+ }
+
+ // memset(&ifr, 0, sizeof(ifr));
+ // ioctl(fd, SIOCGIFFLAGS, &ifr);
+ // ifr.ifr_flags |= IFF_PROMISC;
+ // ioctl(fd, SIOCSIFFLAGS, &ifr);
+
+ link_layer_address_.sll_family = AF_PACKET;
+ link_layer_address_.sll_protocol = htons(ETH_P_ALL);
+ link_layer_address_.sll_ifindex = if_nametoindex(interface_name.c_str());
+ link_layer_address_.sll_hatype = 1;
+ link_layer_address_.sll_halen = 6;
+
+ // startConnectionTimer();
+ doConnect();
+ doRecvPacket();
+}
+
+void RawSocketConnector::state() { return; }
+
+void RawSocketConnector::send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent) {
+ // asio::async_write(socket_, asio::buffer(packet, len),
+ // [packet_sent] (std::error_code ec,
+ // std::size_t /*length*/) {
+ // packet_sent();
+ // });
+}
+
+void RawSocketConnector::send(const Packet::MemBufPtr &packet) {
+ // Packet &p = const_cast<Packet &>(packet);
+ // p.setTcpChecksum();
+
+ // if (!p.checkIntegrity()) {
+ // TRANSPORT_LOGW("Sending message with wrong checksum!!!");
+ // }
+
+ // std::shared_ptr<const Packet> ptr;
+ // try {
+ // ptr = packet.shared_from_this();
+ // } catch (std::bad_weak_ptr& exc) {
+ // TRANSPORT_LOGW("Sending interest which has not been created using a
+ // shared PTR! A copy will be made."); ptr =
+ // std::shared_ptr<Packet>(packet.clone());
+ // }
+
+ io_service_.post([this, packet]() {
+ bool write_in_progress = !output_buffer_.empty();
+ output_buffer_.push_back(std::move(packet));
+ if (!write_in_progress) {
+ doSendPacket();
+ } else {
+ // Tell the handle connect it has data to write
+ data_available_ = true;
+ }
+ });
+}
+
+void RawSocketConnector::close() {
+ io_service_.post([this]() { socket_.close(); });
+}
+
+void RawSocketConnector::doSendPacket() {
+ auto packet = output_buffer_.front().get();
+ auto array = std::vector<asio::const_buffer>();
+
+ const utils::MemBuf *current = packet;
+ do {
+ array.push_back(asio::const_buffer(current->data(), current->length()));
+ current = current->next();
+ } while (current != packet);
+
+ socket_.async_send(
+ std::move(array),
+ [this /*, packet*/](std::error_code ec, std::size_t bytes_transferred) {
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ output_buffer_.pop_front();
+ if (!output_buffer_.empty()) {
+ doSendPacket();
+ }
+ } else {
+ TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ }
+ });
+}
+
+void RawSocketConnector::doRecvPacket() {
+ read_msg_ = std::move(getPacket());
+ socket_.async_receive(
+ asio::buffer(read_msg_->writableData(), packet_size),
+ [this](std::error_code ec, std::size_t bytes_transferred) mutable {
+ if (!ec) {
+ // Ignore packets that are not for us
+ uint8_t *dst_mac_address = const_cast<uint8_t *>(read_msg_->data());
+ if (!std::memcmp(dst_mac_address, ethernet_header_.ether_shost,
+ ETHER_ADDR_LEN)) {
+ read_msg_->append(bytes_transferred);
+ read_msg_->trimStart(sizeof(struct ether_header));
+ receive_callback_(std::move(read_msg_));
+ }
+ } else {
+ TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ }
+ doRecvPacket();
+ });
+}
+
+void RawSocketConnector::doConnect() {
+ socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_)));
+}
+
+void RawSocketConnector::enableBurst() { return; }
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.h b/libtransport/src/hicn/transport/core/raw_socket_connector.h
new file mode 100755
index 000000000..5e39efa0e
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/raw_socket_connector.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/name.h>
+
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <asio.hpp>
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+using asio::generic::raw_protocol;
+using raw_endpoint = asio::generic::basic_endpoint<raw_protocol>;
+
+class RawSocketConnector : public Connector {
+ public:
+ RawSocketConnector(PacketReceivedCallback &&receive_callback,
+ OnReconnect &&reconnect_callback,
+ asio::io_service &io_service,
+ std::string app_name = "Libtransport");
+
+ ~RawSocketConnector() override;
+
+ void send(const Packet::MemBufPtr &packet) override;
+
+ void send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent = 0) override;
+
+ void close() override;
+
+ void enableBurst() override;
+
+ void connect(const std::string &interface_name,
+ const std::string &mac_address_str);
+
+ void state() override;
+
+ private:
+ void doConnect();
+
+ void doRecvPacket();
+
+ void doSendPacket();
+
+ private:
+ asio::io_service &io_service_;
+ raw_protocol::socket socket_;
+
+ struct ether_header ethernet_header_;
+
+ struct sockaddr_ll link_layer_address_;
+
+ asio::steady_timer timer_;
+
+ utils::ObjectPool<utils::MemBuf>::Ptr read_msg_;
+
+ bool data_available_;
+
+ PacketReceivedCallback receive_callback_;
+ OnReconnect on_reconnect_callback_;
+ std::string app_name_;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.cc b/libtransport/src/hicn/transport/core/raw_socket_interface.cc
new file mode 100755
index 000000000..37aaff7e0
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/raw_socket_interface.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/raw_socket_interface.h>
+#include <hicn/transport/utils/linux.h>
+
+#include <fstream>
+
+namespace transport {
+
+namespace core {
+
+static std::string config_folder_path = "/etc/transport/interface.conf.d";
+
+RawSocketInterface::RawSocketInterface(RawSocketConnector &connector)
+ : ForwarderInterface<RawSocketInterface, RawSocketConnector>(connector) {}
+
+RawSocketInterface::~RawSocketInterface() {}
+
+void RawSocketInterface::connect(bool is_consumer) {
+ std::string complete_filename =
+ config_folder_path + std::string("/") + output_interface_;
+
+ std::ifstream is(complete_filename);
+ std::string interface;
+
+ if (is) {
+ is >> remote_mac_address_;
+ }
+
+ // Get interface ip address
+ struct sockaddr_in6 address;
+ utils::retrieveInterfaceAddress(output_interface_, &address);
+ inet6_address_.family = address.sin6_family;
+
+ std::memcpy(inet6_address_.buffer, &address.sin6_addr,
+ sizeof(address.sin6_addr));
+ connector_.connect(output_interface_, remote_mac_address_);
+}
+
+void RawSocketInterface::registerRoute(Prefix &prefix) { return; }
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.h b/libtransport/src/hicn/transport/core/raw_socket_interface.h
new file mode 100755
index 000000000..c030af662
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/raw_socket_interface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/raw_socket_connector.h>
+
+#include <atomic>
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class RawSocketInterface
+ : public ForwarderInterface<RawSocketInterface, RawSocketConnector> {
+ public:
+ typedef RawSocketConnector ConnectorType;
+
+ RawSocketInterface(RawSocketConnector &connector);
+
+ ~RawSocketInterface();
+
+ void connect(bool is_consumer);
+
+ void registerRoute(Prefix &prefix);
+
+ std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+ static constexpr std::uint16_t interface_mtu = 1500;
+ std::string remote_mac_address_;
+};
+
+} // namespace core
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/core/socket_connector.cc b/libtransport/src/hicn/transport/core/socket_connector.cc
new file mode 100755
index 000000000..332b87ec7
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/socket_connector.cc
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/log.h>
+#include <hicn/transport/utils/object_pool.h>
+
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+class NetworkMessage {
+ public:
+ static constexpr std::size_t fixed_header_length = 10;
+
+ static std::size_t decodeHeader(const uint8_t *packet) {
+ // General checks
+ // CCNX Control packet format
+ uint8_t first_byte = packet[0];
+ uint8_t ip_format = (packet[0] & 0xf0) >> 4;
+
+ if (TRANSPORT_EXPECT_FALSE(first_byte == 102)) {
+ // Get packet length
+ return 44;
+ } else if (TRANSPORT_EXPECT_TRUE(ip_format == 6 || ip_format == 4)) {
+ Packet::Format format = Packet::getFormatFromBuffer(packet);
+ return Packet::getHeaderSizeFromBuffer(format, packet) +
+ Packet::getPayloadSizeFromBuffer(format, packet);
+ }
+
+ return 0;
+ }
+};
+} // namespace
+
+SocketConnector::SocketConnector(PacketReceivedCallback &&receive_callback,
+ OnReconnect &&on_reconnect_callback,
+ asio::io_service &io_service,
+ std::string app_name)
+ : Connector(),
+ io_service_(io_service),
+ socket_(io_service_),
+ resolver_(io_service_),
+ timer_(io_service_),
+ read_msg_(packet_pool_.makePtr(nullptr)),
+ is_connecting_(false),
+ is_reconnection_(false),
+ data_available_(false),
+ receive_callback_(receive_callback),
+ on_reconnect_callback_(on_reconnect_callback),
+ app_name_(app_name) {}
+
+SocketConnector::~SocketConnector() {}
+
+void SocketConnector::connect(std::string ip_address, std::string port) {
+ endpoint_iterator_ = resolver_.resolve(
+ {ip_address, port, asio::ip::resolver_query_base::numeric_service});
+
+ startConnectionTimer();
+ doConnect();
+}
+
+void SocketConnector::state() { return; }
+
+void SocketConnector::send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent) {
+ asio::async_write(socket_, asio::buffer(packet, len),
+ [packet_sent](std::error_code ec, std::size_t /*length*/) {
+ packet_sent();
+ });
+}
+
+void SocketConnector::send(const Packet::MemBufPtr &packet) {
+ io_service_.post([this, packet]() {
+ bool write_in_progress = !output_buffer_.empty();
+ output_buffer_.push_back(std::move(packet));
+ if (TRANSPORT_EXPECT_FALSE(!is_connecting_)) {
+ if (!write_in_progress) {
+ doWrite();
+ }
+ } else {
+ // Tell the handle connect it has data to write
+ data_available_ = true;
+ }
+ });
+}
+
+void SocketConnector::close() {
+ io_service_.post([this]() { socket_.close(); });
+}
+
+void SocketConnector::doWrite() {
+ // TODO improve this piece of code for sending many buffers togethers
+ // if list contains more than one packet
+ auto packet = output_buffer_.front().get();
+ auto array = std::vector<asio::const_buffer>();
+
+ const utils::MemBuf *current = packet;
+ do {
+ array.push_back(asio::const_buffer(current->data(), current->length()));
+ current = current->next();
+ } while (current != packet);
+
+ asio::async_write(
+ socket_, std::move(array),
+ [this /*, packet*/](std::error_code ec, std::size_t length) {
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ output_buffer_.pop_front();
+ if (!output_buffer_.empty()) {
+ doWrite();
+ }
+ } else {
+ TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ tryReconnect();
+ }
+ });
+}
+
+void SocketConnector::doReadBody(std::size_t body_length) {
+ asio::async_read(
+ socket_, asio::buffer(read_msg_->writableTail(), body_length),
+ asio::transfer_exactly(body_length),
+ [this](std::error_code ec, std::size_t length) {
+ read_msg_->append(length);
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ receive_callback_(std::move(read_msg_));
+ doReadHeader();
+ } else {
+ TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ tryReconnect();
+ }
+ });
+}
+
+void SocketConnector::doReadHeader() {
+ read_msg_ = getPacket();
+ asio::async_read(
+ socket_,
+ asio::buffer(read_msg_->writableData(),
+ NetworkMessage::fixed_header_length),
+ asio::transfer_exactly(NetworkMessage::fixed_header_length),
+ [this](std::error_code ec, std::size_t length) {
+ if (TRANSPORT_EXPECT_TRUE(!ec)) {
+ read_msg_->append(NetworkMessage::fixed_header_length);
+ std::size_t body_length = 0;
+ if ((body_length = NetworkMessage::decodeHeader(read_msg_->data())) >
+ 0) {
+ doReadBody(body_length - length);
+ } else {
+ TRANSPORT_LOGE("Decoding error. Ignoring packet.");
+ }
+ } else {
+ TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ tryReconnect();
+ }
+ });
+}
+
+void SocketConnector::tryReconnect() {
+ if (!is_connecting_) {
+ TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n");
+ is_connecting_ = true;
+ is_reconnection_ = true;
+ io_service_.post([this]() {
+ socket_.close();
+ startConnectionTimer();
+ doConnect();
+ });
+ }
+}
+
+void SocketConnector::doConnect() {
+ asio::async_connect(socket_, endpoint_iterator_,
+ [this](std::error_code ec, tcp::resolver::iterator) {
+ if (!ec) {
+ timer_.cancel();
+ is_connecting_ = false;
+ asio::ip::tcp::no_delay noDelayOption(true);
+ socket_.set_option(noDelayOption);
+ doReadHeader();
+
+ if (data_available_) {
+ data_available_ = false;
+ doWrite();
+ }
+
+ if (is_reconnection_) {
+ is_reconnection_ = false;
+ TRANSPORT_LOGI("Connection recovered!\n");
+ on_reconnect_callback_();
+ }
+ } else {
+ sleep(1);
+ doConnect();
+ }
+ });
+}
+
+bool SocketConnector::checkConnected() { return !is_connecting_; }
+
+void SocketConnector::enableBurst() { return; }
+
+void SocketConnector::startConnectionTimer() {
+ timer_.expires_from_now(std::chrono::seconds(60));
+ timer_.async_wait(
+ std::bind(&SocketConnector::handleDeadline, this, std::placeholders::_1));
+}
+
+void SocketConnector::handleDeadline(const std::error_code &ec) {
+ if (!ec) {
+ io_service_.post([this]() {
+ socket_.close();
+ TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n");
+ io_service_.stop();
+ });
+ }
+}
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/socket_connector.h b/libtransport/src/hicn/transport/core/socket_connector.h
new file mode 100755
index 000000000..d7a05aab4
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/socket_connector.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <asio.hpp>
+#include <deque>
+
+namespace transport {
+namespace core {
+
+using asio::ip::tcp;
+
+class SocketConnector : public Connector {
+ public:
+ SocketConnector(PacketReceivedCallback &&receive_callback,
+ OnReconnect &&reconnect_callback,
+ asio::io_service &io_service,
+ std::string app_name = "Libtransport");
+
+ ~SocketConnector() override;
+
+ void send(const Packet::MemBufPtr &packet) override;
+
+ void send(const uint8_t *packet, std::size_t len,
+ const PacketSentCallback &packet_sent = 0) override;
+
+ void close() override;
+
+ void enableBurst() override;
+
+ void connect(std::string ip_address = "127.0.0.1", std::string port = "9695");
+
+ void state() override;
+
+ private:
+ void doConnect();
+
+ void doReadHeader();
+
+ void doReadBody(std::size_t body_length);
+
+ void doWrite();
+
+ bool checkConnected();
+
+ private:
+ void handleDeadline(const std::error_code &ec);
+
+ void startConnectionTimer();
+
+ void tryReconnect();
+
+ asio::io_service &io_service_;
+ asio::ip::tcp::socket socket_;
+ asio::ip::tcp::resolver resolver_;
+ asio::ip::tcp::resolver::iterator endpoint_iterator_;
+ asio::steady_timer timer_;
+
+ utils::ObjectPool<utils::MemBuf>::Ptr read_msg_;
+
+ bool is_connecting_;
+ bool is_reconnection_;
+ bool data_available_;
+
+ PacketReceivedCallback receive_callback_;
+ OnReconnect on_reconnect_callback_;
+ std::string app_name_;
+};
+
+} // end namespace core
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/test/CMakeLists.txt b/libtransport/src/hicn/transport/core/test/CMakeLists.txt
new file mode 100755
index 000000000..48c50e9b0
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/test/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_core_manifest)
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach() \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/test/test_core_manifest.cc b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc
new file mode 100755
index 000000000..58563d8f9
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2017-2019 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 <gtest/gtest.h>
+
+#include "../manifest_format_fixed.h"
+#include "../manifest_inline.h"
+
+#include <test.h>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+// The fixture for testing class Foo.
+class ManifestTest : public ::testing::Test {
+ protected:
+ using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
+
+ ManifestTest() : name_("b001::123|321"), manifest1_(name_) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~ManifestTest() {
+ // You can do clean-up work that doesn't throw exceptions here.
+ }
+
+ // If the constructor and destructor are not enough for setting up
+ // and cleaning up each test, you can define the following methods:
+
+ virtual void SetUp() {
+ // Code here will be called immediately after the constructor (right
+ // before each test).
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ }
+
+ Name name_;
+ ContentObjectManifest manifest1_;
+
+ std::vector<uint8_t> manifest_payload = {
+ 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00,
+ // 0x00, 0x45, 0xa3,
+ // 0xd1, 0xf2, 0x2b,
+ // 0x94, 0x41, 0x22,
+ // 0xc9, 0x00, 0x00,
+ // 0x00, 0x44, 0xa3,
+ // 0xd1, 0xf2, 0x2b,
+ // 0x94, 0x41, 0x22,
+ // 0xc8
+ };
+};
+
+} // namespace
+
+TEST_F(ManifestTest, ManifestCreate) {
+ ContentObjectManifest manifest2(name_);
+ ContentObjectManifest manifest3 = manifest2;
+
+ EXPECT_EQ(manifest1_, manifest2);
+ EXPECT_EQ(manifest1_, manifest3);
+}
+
+TEST_F(ManifestTest, ManifestCreateFromBase) {
+ ContentObject content_object(name_);
+ content_object.setPayload(manifest_payload.data(), manifest_payload.size());
+ ContentObjectManifest manifest(std::move(content_object));
+
+ auto manifest4 = ContentObjectManifest::createManifest(
+ name_, core::ManifestVersion::VERSION_1,
+ core::ManifestType::INLINE_MANIFEST, HashAlgorithm::SHA_256, true,
+ core::Name("b001::dead"),
+ core::NextSegmentCalculationStrategy::INCREMENTAL, 128);
+
+ manifest4->encode();
+ manifest4->dump();
+ manifest.dump();
+
+ EXPECT_EQ(manifest1_, manifest);
+ // EXPECT_EQ(manifest1_, manifest3);
+}
+
+TEST_F(ManifestTest, SetLastManifest) {
+ manifest1_.clear();
+
+ manifest1_.setFinalManifest(true);
+ manifest1_.encode();
+ manifest1_.decode();
+ bool fcn = manifest1_.isFinalManifest();
+
+ ASSERT_TRUE(fcn);
+}
+
+TEST_F(ManifestTest, SetManifestType) {
+ manifest1_.clear();
+
+ ManifestType type1 = ManifestType::INLINE_MANIFEST;
+ ManifestType type2 = ManifestType::FLIC_MANIFEST;
+
+ manifest1_.setManifestType(type1);
+ manifest1_.encode();
+ manifest1_.decode();
+ ManifestType type_returned1 = manifest1_.getManifestType();
+
+ manifest1_.clear();
+
+ manifest1_.setManifestType(type2);
+ manifest1_.encode();
+ manifest1_.decode();
+ ManifestType type_returned2 = manifest1_.getManifestType();
+
+ ASSERT_EQ(type1, type_returned1);
+ ASSERT_EQ(type2, type_returned2);
+}
+
+TEST_F(ManifestTest, SetHashAlgorithm) {
+ manifest1_.clear();
+
+ HashAlgorithm hash1 = HashAlgorithm::SHA_512;
+ HashAlgorithm hash2 = HashAlgorithm::CRC32C;
+ HashAlgorithm hash3 = HashAlgorithm::SHA_256;
+
+ manifest1_.setHashAlgorithm(hash1);
+ manifest1_.encode();
+ manifest1_.decode();
+ HashAlgorithm type_returned1 = manifest1_.getHashAlgorithm();
+
+ manifest1_.clear();
+
+ manifest1_.setHashAlgorithm(hash2);
+ manifest1_.encode();
+ manifest1_.decode();
+ HashAlgorithm type_returned2 = manifest1_.getHashAlgorithm();
+
+ manifest1_.clear();
+
+ manifest1_.setHashAlgorithm(hash3);
+ manifest1_.encode();
+ manifest1_.decode();
+ HashAlgorithm type_returned3 = manifest1_.getHashAlgorithm();
+
+ ASSERT_EQ(hash1, type_returned1);
+ ASSERT_EQ(hash2, type_returned2);
+ ASSERT_EQ(hash3, type_returned3);
+}
+
+TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) {
+ manifest1_.clear();
+
+ NextSegmentCalculationStrategy strategy1 =
+ NextSegmentCalculationStrategy::INCREMENTAL;
+
+ manifest1_.setNextSegmentCalculationStrategy(strategy1);
+ manifest1_.encode();
+ manifest1_.decode();
+ NextSegmentCalculationStrategy type_returned1 =
+ manifest1_.getNextSegmentCalculationStrategy();
+
+ ASSERT_EQ(strategy1, type_returned1);
+}
+
+TEST_F(ManifestTest, SetBaseName) {
+ manifest1_.clear();
+
+ core::Name base_name("b001::dead");
+ manifest1_.setBaseName(base_name);
+ manifest1_.encode();
+ manifest1_.decode();
+ core::Name ret_name = manifest1_.getBaseName();
+
+ ASSERT_EQ(base_name, ret_name);
+}
+
+TEST_F(ManifestTest, SetSuffixList) {
+ manifest1_.clear();
+
+ core::Name base_name("b001::dead");
+
+ using random_bytes_engine =
+ std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
+ unsigned char>;
+ random_bytes_engine rbe;
+
+ std::default_random_engine eng((std::random_device())());
+ std::uniform_int_distribution<uint64_t> idis(
+ 0, std::numeric_limits<uint32_t>::max());
+
+ auto entries = new std::pair<uint32_t, utils::CryptoHash>[3];
+ uint32_t suffixes[3];
+ std::vector<unsigned char> data[3];
+
+ for (int i = 0; i < 3; i++) {
+ data[i].resize(32);
+ std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe));
+ suffixes[i] = idis(eng);
+ entries[i] = std::make_pair(
+ suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(),
+ utils::CryptoHashType::SHA_256));
+ manifest1_.addSuffixHash(entries[i].first, entries[i].second);
+ }
+
+ manifest1_.setBaseName(base_name);
+
+ manifest1_.encode();
+ manifest1_.decode();
+
+ core::Name ret_name = manifest1_.getBaseName();
+
+ // auto & hash_list = manifest1_.getSuffixHashList();
+
+ bool cond;
+ int i = 0;
+
+ // for (auto & item : manifest1_.getSuffixList()) {
+ // auto hash = manifest1_.getHash(suffixes[i]);
+ // cond = utils::CryptoHash::compareBinaryDigest(hash,
+ // entries[i].second.getDigest<uint8_t>().data(),
+ // entries[i].second.getType());
+ // ASSERT_TRUE(cond);
+ // i++;
+ // }
+
+ ASSERT_EQ(base_name, ret_name);
+
+ delete[] entries;
+}
+
+TEST_F(ManifestTest, EstimateSize) {
+ manifest1_.clear();
+
+ HashAlgorithm hash1 = HashAlgorithm::SHA_256;
+ NextSegmentCalculationStrategy strategy1 =
+ NextSegmentCalculationStrategy::INCREMENTAL;
+ ManifestType type1 = ManifestType::INLINE_MANIFEST;
+ core::Name base_name1("b001:abcd:fede:baba:cece:d0d0:face:dead");
+
+ manifest1_.setFinalManifest(true);
+ manifest1_.setBaseName(base_name1);
+ manifest1_.setNextSegmentCalculationStrategy(strategy1);
+ manifest1_.setHashAlgorithm(hash1);
+ manifest1_.setManifestType(type1);
+
+ std::default_random_engine eng((std::random_device())());
+ std::uniform_int_distribution<uint64_t> idis(
+ 0, std::numeric_limits<uint64_t>::max());
+
+ using random_bytes_engine =
+ std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
+ unsigned char>;
+ random_bytes_engine rbe;
+
+ while (manifest1_.estimateManifestSize(1) < 1440) {
+ uint32_t suffix = static_cast<std::uint32_t>(idis(eng));
+ std::vector<unsigned char> data(32);
+ std::generate(std::begin(data), std::end(data), std::ref(rbe));
+ auto hash = utils::CryptoHash(data.data(), data.size(),
+ utils::CryptoHashType::SHA_256);
+ manifest1_.addSuffixHash(suffix, hash);
+ }
+
+ manifest1_.encode();
+ manifest1_.decode();
+
+ manifest1_.dump();
+
+ ASSERT_GT(manifest1_.estimateManifestSize(), 0);
+ ASSERT_LT(manifest1_.estimateManifestSize(), 1500);
+}
+
+} // namespace core
+
+} // namespace transport
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+} \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.c b/libtransport/src/hicn/transport/core/vpp_binary_api.c
new file mode 100755
index 000000000..ab23d3cf5
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/vpp_binary_api.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/vpp_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/ip/ip.h>
+#include <vppinfra/error.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#define vl_typedefs
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+/* Get CRC codes of the messages */
+#define vl_msg_name_crc_list
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+// #define vl_api_version(n,v) static u32 vpe_api_version = (v);
+// #include <vpp/api/vpe.api.h>
+// #undef vl_api_version
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_memif_api_reply_msg \
+ _(MEMIF_CREATE_REPLY, memif_create_reply) \
+ _(MEMIF_DELETE_REPLY, memif_delete_reply) \
+ _(MEMIF_DETAILS, memif_details)
+
+/**
+ * @brief Generic VPP request structure.
+ */
+typedef struct __attribute__((packed)) vl_generic_request_s {
+ u16 _vl_msg_id;
+ u32 client_index;
+ u32 context;
+} vl_generic_request_t;
+
+/**
+ * @brief Generic VPP reply structure (response with a single message).
+ */
+typedef struct __attribute__((packed)) vl_generic_reply_s {
+ u16 _vl_msg_id;
+ u32 context;
+ i32 retval;
+} vl_generic_reply_t;
+
+static void vl_api_control_ping_reply_t_handler(
+ vl_api_control_ping_reply_t *mp) {
+ // Just unblock main thread
+ vpp_binary_api_t *binary_api = global_pointers_map[mp->context];
+ binary_api->ret_val = ntohl(mp->retval);
+ vpp_binary_api_unlock_waiting_thread(binary_api);
+}
+
+static void vl_api_sw_interface_set_flags_reply_t_handler(
+ vl_api_control_ping_reply_t *mp) {
+ // Unblock main thread setting reply message status code
+ vpp_binary_api_t *binary_api = global_pointers_map[mp->context];
+ binary_api->ret_val = ntohl(mp->retval);
+ vpp_binary_api_unlock_waiting_thread(binary_api);
+}
+
+static int vpp_connect_to_vlib(vpp_binary_api_t *binary_api, char *name) {
+ clib_mem_init_thread_safe(0, 256 << 20);
+ if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0) {
+ return -1;
+ }
+
+ binary_api->vl_input_queue = binary_api->api_main->shmem_hdr->vl_input_queue;
+ binary_api->my_client_index = binary_api->api_main->my_client_index;
+
+ return 0;
+}
+
+vpp_binary_api_t *vpp_binary_api_init(const char *app_name) {
+ vpp_binary_api_t *ret = malloc(sizeof(vpp_binary_api_t));
+ ret->api_main = &api_main;
+ ret->vlib_main = &vlib_global_main;
+
+ vpp_connect_to_vlib(ret, (char *)app_name);
+ ret->semaphore = sem_open(app_name, O_CREAT, 0, 0);
+
+ return ret;
+}
+
+void vpp_binary_api_destroy(vpp_binary_api_t *api) {
+ sem_close(api->semaphore);
+ free(api);
+ vl_client_disconnect_from_vlib();
+}
+
+void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t *api) {
+ sem_post(api->semaphore);
+}
+
+void vpp_binary_api_send_receive_ping(vpp_binary_api_t *api) {
+ /* Use a control ping for synchronization */
+
+ /* Get the control ping ID */
+#define _(id, n, crc) \
+ const char *id##_CRC __attribute__((unused)) = #n "_" #crc;
+ foreach_vl_msg_name_crc_vpe;
+#undef _
+
+ int ping_reply_id =
+ vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_REPLY_CRC));
+ vl_msg_api_set_handlers(ping_reply_id, "control_ping_reply",
+ vl_api_control_ping_reply_t_handler, vl_noop_handler,
+ vl_api_control_ping_reply_t_endian,
+ vl_api_control_ping_reply_t_print,
+ sizeof(vl_api_control_ping_reply_t), 1);
+
+ vl_api_control_ping_t *mp_ping;
+ mp_ping = vl_msg_api_alloc_as_if_client(sizeof(*mp_ping));
+ mp_ping->_vl_msg_id = clib_host_to_net_u16(
+ vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_CRC)));
+ mp_ping->client_index = api->my_client_index;
+
+ global_pointers_map[global_pointers_map_index] = api;
+ mp_ping->context = global_pointers_map_index++;
+ global_pointers_map_index %= POINTER_MAP_SIZE;
+
+ TRANSPORT_LOGI("Sending ping id %u", mp_ping->_vl_msg_id);
+
+ vpp_binary_api_send_request_wait_reply(api, mp_ping);
+}
+
+int vpp_binary_api_set_int_state(vpp_binary_api_t *api, uint32_t sw_index,
+ link_state_t state) {
+#define _(id, n, crc) \
+ const char *id##_CRC __attribute__((unused)) = #n "_" #crc;
+ foreach_vl_msg_name_crc_vpe;
+#undef _
+
+ int sw_interface_set_flags_reply_id = VL_API_SW_INTERFACE_SET_FLAGS_REPLY;
+ vl_msg_api_set_handlers(
+ sw_interface_set_flags_reply_id, "sw_interface_set_flags_reply",
+ vl_api_sw_interface_set_flags_reply_t_handler, vl_noop_handler,
+ vl_api_sw_interface_set_flags_reply_t_endian,
+ vl_api_sw_interface_set_flags_reply_t_print,
+ sizeof(vl_api_sw_interface_set_flags_reply_t), 1);
+
+ vl_api_sw_interface_set_flags_t *mp;
+ mp = vl_msg_api_alloc_as_if_client(sizeof(*mp));
+ mp->_vl_msg_id = clib_host_to_net_u16(VL_API_SW_INTERFACE_SET_FLAGS);
+ mp->client_index = api->my_client_index;
+ mp->sw_if_index = clib_host_to_net_u32(sw_index);
+ mp->admin_up_down = (u8)state;
+
+ global_pointers_map[global_pointers_map_index] = api;
+ mp->context = global_pointers_map_index++;
+ global_pointers_map_index %= POINTER_MAP_SIZE;
+
+ TRANSPORT_LOGI("Sending set int flags id %u", mp->_vl_msg_id);
+
+ return vpp_binary_api_send_request_wait_reply(api, mp);
+}
+
+void vpp_binary_api_send_request(vpp_binary_api_t *api, void *request) {
+ vl_generic_request_t *req = NULL;
+
+ req = (vl_generic_request_t *)request;
+ TRANSPORT_LOGI("Sending a request to VPP (id=%d).\n", ntohs(req->_vl_msg_id));
+
+ S(api, req);
+}
+
+int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t *api,
+ void *request) {
+ vpp_binary_api_send_request(api, request);
+
+ sem_wait(api->semaphore);
+
+ return api->ret_val;
+}
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.h b/libtransport/src/hicn/transport/core/vpp_binary_api.h
new file mode 100755
index 000000000..1eb10e766
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/vpp_binary_api.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct vpp_binary_api vpp_binary_api_t;
+typedef struct vpp_plugin_binary_api vpp_plugin_binary_api_t;
+
+typedef enum link_state_s { UP = 1, DOWN = 0 } link_state_t;
+
+/**
+ * @brief Instantiate a new vpp_binary_api_t data structure and
+ * connect the application to the local VPP forwarder.
+ */
+vpp_binary_api_t* vpp_binary_api_init(const char* app_name);
+
+/**
+ * @brief Destroy the vpp_binary_api_t and disconnect from VPP.
+ */
+void vpp_binary_api_destroy(vpp_binary_api_t* api);
+
+void vpp_binary_api_send_receive_ping(vpp_binary_api_t* api);
+
+int vpp_binary_api_set_int_state(vpp_binary_api_t* api, uint32_t sw_index,
+ link_state_t state);
+
+/**
+ * @brief Send request to VPP and wait for reply.
+ */
+int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t* api,
+ void* request);
+
+void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t* api);
+
+void vpp_binary_api_send_request(vpp_binary_api_t* api, void* request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h b/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h
new file mode 100755
index 000000000..22b665e96
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <semaphore.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+struct vpp_binary_api {
+ api_main_t *api_main;
+ u32 my_client_index;
+ unix_shared_memory_queue_t *vl_input_queue;
+ vlib_main_t *vlib_main;
+ sem_t *semaphore;
+ u32 ping_id;
+ int ret_val;
+ void *user_param;
+};
+
+struct vpp_plugin_binary_api {
+ vpp_binary_api_t *vpp_api;
+ u16 msg_id_base;
+ u32 my_client_index;
+};
+
+#define M(T, mp) \
+ do { \
+ mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)); \
+ memset(mp, 0, sizeof(*mp)); \
+ mp->_vl_msg_id = ntohs(VL_API_##T + hm->msg_id_base); \
+ mp->client_index = hm->my_client_index; \
+ } while (0);
+
+#define S(api, mp) (vl_msg_api_send_shmem(api->vl_input_queue, (u8 *)&mp))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
new file mode 100755
index 000000000..3a748c821
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/memif_binary_api.h>
+#include <hicn/transport/core/vpp_forwarder_interface.h>
+
+typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t;
+
+#define MEMIF_DEFAULT_RING_SIZE 2048
+#define MEMIF_DEFAULT_RX_QUEUES 1
+#define MEMIF_DEFAULT_TX_QUEUES 1
+#define MEMIF_DEFAULT_BUFFER_SIZE 2048
+
+namespace transport {
+
+namespace core {
+
+vpp_binary_api_t *VPPForwarderInterface::api_ = nullptr;
+vpp_plugin_binary_api_t *VPPForwarderInterface::memif_api_ = nullptr;
+vpp_plugin_binary_api_t *VPPForwarderInterface::hicn_api_ = nullptr;
+std::mutex VPPForwarderInterface::global_lock_;
+
+VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector)
+ : ForwarderInterface<VPPForwarderInterface, MemifConnector>(connector),
+ sw_if_index_(~0),
+ face_id_(~0) {}
+
+VPPForwarderInterface::~VPPForwarderInterface() {}
+
+/**
+ * @brief Create a memif interface in the local VPP forwarder.
+ */
+uint32_t VPPForwarderInterface::getMemifConfiguration() {
+ memif_create_params_t input_params = {0};
+
+ memif_id_ =
+ memif_binary_api_get_next_memif_id(VPPForwarderInterface::memif_api_);
+
+ input_params.id = memif_id_;
+ input_params.role = memif_role_t::MASTER;
+ input_params.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
+ input_params.rx_queues = MEMIF_DEFAULT_RX_QUEUES;
+ input_params.tx_queues = MEMIF_DEFAULT_TX_QUEUES;
+ input_params.ring_size = MEMIF_DEFAULT_RING_SIZE;
+ input_params.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+ memif_output_params_t output_params = {0};
+
+ if (memif_binary_api_create_memif(VPPForwarderInterface::memif_api_,
+ &input_params, &output_params) < 0) {
+ throw errors::RuntimeException(
+ "Error creating memif interface in the local VPP forwarder.");
+ }
+
+ return output_params.sw_if_index;
+}
+
+void VPPForwarderInterface::consumerConnection() {
+ hicn_consumer_input_params input = {0};
+ hicn_consumer_output_params output;
+
+ std::memset(&output, 0, sizeof(hicn_consumer_output_params));
+
+ input.swif = sw_if_index_;
+
+ if (int ret = hicn_binary_api_register_cons_app(
+ VPPForwarderInterface::hicn_api_, &input, &output) < 0) {
+ throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+ }
+
+ inet_address_.family = AF_INET;
+ inet_address_.prefix_len = output.src4.prefix_length;
+ std::memcpy(inet_address_.buffer, output.src4.ip4.as_u8, IPV4_ADDR_LEN);
+
+ inet6_address_.family = AF_INET6;
+ inet6_address_.prefix_len = output.src6.prefix_length;
+ std::memcpy(inet6_address_.buffer, output.src6.ip6.as_u8, IPV6_ADDR_LEN);
+}
+
+void VPPForwarderInterface::producerConnection() {
+ // Producer connection will be set when we set the first route.
+}
+
+void VPPForwarderInterface::connect(bool is_consumer) {
+ std::lock_guard<std::mutex> connection_lock(global_lock_);
+
+ srand(time(NULL));
+ int secret = rand() % (1 << 10);
+ std::stringstream app_name;
+ app_name << "Libtransport_" << secret;
+
+ if (!VPPForwarderInterface::memif_api_) {
+ VPPForwarderInterface::api_ = vpp_binary_api_init(app_name.str().c_str());
+ }
+
+ VPPForwarderInterface::memif_api_ =
+ memif_binary_api_init(VPPForwarderInterface::api_);
+
+ sw_if_index_ = getMemifConfiguration();
+
+ VPPForwarderInterface::hicn_api_ =
+ hicn_binary_api_init(VPPForwarderInterface::api_);
+ if (is_consumer) {
+ consumerConnection();
+ }
+
+ connector_.connect(memif_id_, 0);
+}
+
+void VPPForwarderInterface::registerRoute(Prefix &prefix) {
+ auto &addr = prefix.toIpAddressStruct();
+
+ if (face_id_ == uint32_t(~0)) {
+ hicn_producer_input_params input;
+ std::memset(&input, 0, sizeof(input));
+
+ hicn_producer_output_params output;
+ std::memset(&output, 0, sizeof(output));
+
+ // Here we have to ask to the actual connector what is the
+ // memif_id, since this function should be called after the
+ // memif creation.
+ input.swif = sw_if_index_;
+ input.prefix.ip6.as_u64[0] = addr.as_u64[0];
+ input.prefix.ip6.as_u64[1] = addr.as_u64[1];
+ input.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4;
+ input.prefix.prefix_length = addr.prefix_len;
+ input.cs_reserved = content_store_reserved_;
+
+ if (int ret = hicn_binary_api_register_prod_app(
+ VPPForwarderInterface::hicn_api_, &input, &output) < 0) {
+ throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+ }
+
+ if (addr.family == AF_INET6) {
+ inet6_address_.prefix_len = output.prod_addr.prefix_length;
+ std::memcpy(inet6_address_.buffer, output.prod_addr.ip6.as_u8,
+ IPV6_ADDR_LEN);
+ } else {
+ inet_address_.prefix_len = output.prod_addr.prefix_length;
+ // The ipv4 is written in the last 4 bytes of the ipv6 address, so we need
+ // to copy from the byte 12
+ std::memcpy(inet_address_.buffer, output.prod_addr.ip6.as_u8 + 12,
+ IPV4_ADDR_LEN);
+ }
+
+ face_id_ = output.face_id;
+ } else {
+ hicn_producer_set_route_params params;
+ params.prefix.ip6.as_u64[0] = addr.as_u64[0];
+ params.prefix.ip6.as_u64[1] = addr.as_u64[1];
+ params.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4;
+ params.prefix.prefix_length = addr.prefix_len;
+ params.face_id = face_id_;
+
+ if (int ret = hicn_binary_api_register_route(
+ VPPForwarderInterface::hicn_api_, &params) < 0) {
+ throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+ }
+ }
+}
+
+} // namespace core
+
+} // namespace transport
+
+#endif \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h
new file mode 100755
index 000000000..322cd1f8b
--- /dev/null
+++ b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/memif_connector.h>
+#include <hicn/transport/core/prefix.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class VPPForwarderInterface
+ : public ForwarderInterface<VPPForwarderInterface, MemifConnector> {
+ public:
+ VPPForwarderInterface(MemifConnector &connector);
+
+ typedef MemifConnector ConnectorType;
+
+ ~VPPForwarderInterface();
+
+ void connect(bool is_consumer);
+
+ void registerRoute(Prefix &prefix);
+
+ TRANSPORT_ALWAYS_INLINE std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+ uint32_t getMemifConfiguration();
+
+ void consumerConnection();
+
+ void producerConnection();
+
+ static vpp_binary_api_t *api_;
+ static vpp_plugin_binary_api_t *memif_api_;
+ static vpp_plugin_binary_api_t *hicn_api_;
+ uint32_t memif_id_;
+ uint32_t sw_if_index_;
+ uint32_t face_id_;
+ static std::mutex global_lock_;
+ static constexpr std::uint16_t interface_mtu = 1500;
+};
+
+} // namespace core
+
+} // namespace transport
+
+#endif \ No newline at end of file