aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar+fdio@cisco.com>2019-01-17 13:47:57 +0100
committerLuca Muscariello <lumuscar+fdio@cisco.com>2019-01-17 16:32:51 +0100
commitbac3da61644515f05663789b122554dc77549286 (patch)
tree898210bc8e70371d77de7d446a26c5dd4fd1165a /libtransport
parentd5165246787301d0f13b646fda5e8a8567aef5ac (diff)
This is the first commit of the hicn projectv19.01
Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'libtransport')
-rwxr-xr-xlibtransport/AUTHORS8
-rwxr-xr-xlibtransport/CMakeLists.txt122
-rwxr-xr-xlibtransport/README.md126
-rwxr-xr-xlibtransport/cmake/Modules/Android.cmake19
-rwxr-xr-xlibtransport/cmake/Modules/DefaultConfiguration.cmake48
-rwxr-xr-xlibtransport/cmake/Modules/Ios.cmake23
-rwxr-xr-xlibtransport/cmake/Modules/Packager.cmake197
-rwxr-xr-xlibtransport/cmake/Modules/TestMacros.cmake15
-rwxr-xr-xlibtransport/src/hicn/transport/CMakeLists.txt54
-rwxr-xr-xlibtransport/src/hicn/transport/config.h.in22
-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
-rwxr-xr-xlibtransport/src/hicn/transport/errors/CMakeLists.txt29
-rwxr-xr-xlibtransport/src/hicn/transport/errors/errors.h24
-rwxr-xr-xlibtransport/src/hicn/transport/errors/invalid_ip_address_exception.h31
-rwxr-xr-xlibtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h31
-rwxr-xr-xlibtransport/src/hicn/transport/errors/malformed_name_exception.h31
-rwxr-xr-xlibtransport/src/hicn/transport/errors/malformed_packet_exception.h29
-rwxr-xr-xlibtransport/src/hicn/transport/errors/not_implemented_exception.h30
-rwxr-xr-xlibtransport/src/hicn/transport/errors/null_pointer_exception.h31
-rwxr-xr-xlibtransport/src/hicn/transport/errors/runtime_exception.h32
-rwxr-xr-xlibtransport/src/hicn/transport/errors/tokenizer_exception.h31
-rwxr-xr-xlibtransport/src/hicn/transport/http/CMakeLists.txt36
-rwxr-xr-xlibtransport/src/hicn/transport/http/callbacks.h46
-rwxr-xr-xlibtransport/src/hicn/transport/http/client_connection.cc194
-rwxr-xr-xlibtransport/src/hicn/transport/http/client_connection.h82
-rwxr-xr-xlibtransport/src/hicn/transport/http/default_values.h32
-rwxr-xr-xlibtransport/src/hicn/transport/http/facade.h22
-rwxr-xr-xlibtransport/src/hicn/transport/http/message.h58
-rwxr-xr-xlibtransport/src/hicn/transport/http/request.cc83
-rwxr-xr-xlibtransport/src/hicn/transport/http/request.h61
-rwxr-xr-xlibtransport/src/hicn/transport/http/response.cc134
-rwxr-xr-xlibtransport/src/hicn/transport/http/response.h58
-rwxr-xr-xlibtransport/src/hicn/transport/http/server_acceptor.cc112
-rwxr-xr-xlibtransport/src/hicn/transport/http/server_acceptor.h62
-rwxr-xr-xlibtransport/src/hicn/transport/http/server_publisher.cc173
-rwxr-xr-xlibtransport/src/hicn/transport/http/server_publisher.h72
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/CMakeLists.txt38
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/async_transport.h640
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/full_duplex_socket.cc490
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/full_duplex_socket.h254
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/publication_options.h34
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc35
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h35
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc157
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/rtc_socket_producer.h60
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket.h270
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_consumer.cc735
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_consumer.h259
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_options_default_values.h68
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_options_keys.h108
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_producer.cc948
-rwxr-xr-xlibtransport/src/hicn/transport/interfaces/socket_producer.h269
-rwxr-xr-xlibtransport/src/hicn/transport/portability/CMakeLists.txt26
-rwxr-xr-xlibtransport/src/hicn/transport/portability/c_portability.h36
-rwxr-xr-xlibtransport/src/hicn/transport/portability/portability.h46
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/CMakeLists.txt46
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/cbr.cc47
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/cbr.h48
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/consumer.conf21
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/download_observer.h32
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/protocol.cc45
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/protocol.h79
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/raaqm.cc416
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/raaqm.h94
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/raaqm_data_path.cc158
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/raaqm_data_path.h230
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rate_estimation.cc353
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rate_estimation.h175
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rtc.cc813
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rtc.h210
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rtc_data_path.cc85
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/rtc_data_path.h62
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/test/CMakeLists.txt10
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/test/test_transport_producer.cc80
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/vegas.cc630
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/vegas.h161
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc57
-rwxr-xr-xlibtransport/src/hicn/transport/protocols/vegas_rto_estimator.h48
-rwxr-xr-xlibtransport/src/hicn/transport/utils/CMakeLists.txt76
-rwxr-xr-xlibtransport/src/hicn/transport/utils/array.h62
-rwxr-xr-xlibtransport/src/hicn/transport/utils/branch_prediction.h22
-rwxr-xr-xlibtransport/src/hicn/transport/utils/content_store.cc109
-rwxr-xr-xlibtransport/src/hicn/transport/utils/content_store.h75
-rwxr-xr-xlibtransport/src/hicn/transport/utils/conversions.h37
-rwxr-xr-xlibtransport/src/hicn/transport/utils/crypto_hash.h115
-rwxr-xr-xlibtransport/src/hicn/transport/utils/crypto_hash_type.h31
-rwxr-xr-xlibtransport/src/hicn/transport/utils/crypto_hasher.h68
-rwxr-xr-xlibtransport/src/hicn/transport/utils/crypto_suite.h35
-rwxr-xr-xlibtransport/src/hicn/transport/utils/daemonizator.cc73
-rwxr-xr-xlibtransport/src/hicn/transport/utils/daemonizator.h25
-rwxr-xr-xlibtransport/src/hicn/transport/utils/deadline_timer.h114
-rwxr-xr-xlibtransport/src/hicn/transport/utils/endianess.h136
-rwxr-xr-xlibtransport/src/hicn/transport/utils/epoll_event_reactor.cc183
-rwxr-xr-xlibtransport/src/hicn/transport/utils/epoll_event_reactor.h65
-rwxr-xr-xlibtransport/src/hicn/transport/utils/event_reactor.h37
-rwxr-xr-xlibtransport/src/hicn/transport/utils/event_thread.h101
-rwxr-xr-xlibtransport/src/hicn/transport/utils/fd_deadline_timer.h127
-rwxr-xr-xlibtransport/src/hicn/transport/utils/hash.h101
-rwxr-xr-xlibtransport/src/hicn/transport/utils/identity.cc130
-rwxr-xr-xlibtransport/src/hicn/transport/utils/identity.h64
-rwxr-xr-xlibtransport/src/hicn/transport/utils/key_id.h25
-rwxr-xr-xlibtransport/src/hicn/transport/utils/linux.h64
-rwxr-xr-xlibtransport/src/hicn/transport/utils/literals.h55
-rwxr-xr-xlibtransport/src/hicn/transport/utils/log.cc1405
-rwxr-xr-xlibtransport/src/hicn/transport/utils/log.h1057
-rwxr-xr-xlibtransport/src/hicn/transport/utils/membuf.cc864
-rwxr-xr-xlibtransport/src/hicn/transport/utils/membuf.h916
-rwxr-xr-xlibtransport/src/hicn/transport/utils/min_filter.h56
-rwxr-xr-xlibtransport/src/hicn/transport/utils/object_pool.h76
-rwxr-xr-xlibtransport/src/hicn/transport/utils/ring_buffer.h129
-rwxr-xr-xlibtransport/src/hicn/transport/utils/sharable_vector.h30
-rwxr-xr-xlibtransport/src/hicn/transport/utils/signer.cc173
-rwxr-xr-xlibtransport/src/hicn/transport/utils/signer.h69
-rwxr-xr-xlibtransport/src/hicn/transport/utils/socket.h267
-rwxr-xr-xlibtransport/src/hicn/transport/utils/spinlock.h53
-rwxr-xr-xlibtransport/src/hicn/transport/utils/stream_buffer.h31
-rwxr-xr-xlibtransport/src/hicn/transport/utils/string_tokenizer.cc47
-rwxr-xr-xlibtransport/src/hicn/transport/utils/string_tokenizer.h35
-rwxr-xr-xlibtransport/src/hicn/transport/utils/test.h46
-rwxr-xr-xlibtransport/src/hicn/transport/utils/uri.cc122
-rwxr-xr-xlibtransport/src/hicn/transport/utils/uri.h47
-rwxr-xr-xlibtransport/src/hicn/transport/utils/verifier.cc193
-rwxr-xr-xlibtransport/src/hicn/transport/utils/verifier.h85
176 files changed, 25944 insertions, 0 deletions
diff --git a/libtransport/AUTHORS b/libtransport/AUTHORS
new file mode 100755
index 000000000..12d1ae699
--- /dev/null
+++ b/libtransport/AUTHORS
@@ -0,0 +1,8 @@
+Libtransport authors are listed below
+
+ Mauro Sardara <msardara@cisco.com>
+ Michele Papalini <micpapal@cisco.com>
+ Alberto Compagno <acompagn@cisco.com>
+ Luca Muscariello <lumuscar@cisco.com>
+
+Copyright (c) 2017-2019 Cisco and/or its affiliates. \ No newline at end of file
diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt
new file mode 100755
index 000000000..f2ade4520
--- /dev/null
+++ b/libtransport/CMakeLists.txt
@@ -0,0 +1,122 @@
+# 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)
+
+project(Transport VERSION 1.0)
+
+set(CMAKE_MODULE_PATH
+ ${CMAKE_MODULE_PATH}
+ "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+)
+
+include(DefaultConfiguration)
+include(Packager)
+include(BuildMacros)
+
+if (NOT CMAKE_BUILD_TYPE)
+ message(STATUS "No build type selected, default to Release")
+ set(CMAKE_BUILD_TYPE "Release")
+endif ()
+
+set(TRANSPORT_ROOT_PATH "src/hicn/transport")
+
+set(TRANSPORT_CORE ${TRANSPORT_ROOT_PATH}/core)
+set(TRANSPORT_TRANSPORT ${TRANSPORT_ROOT_PATH}/transport)
+set(TRANSPORT_ERRORS ${TRANSPORT_ROOT_PATH}/errors)
+set(TRANSPORT_UTILS ${TRANSPORT_ROOT_PATH}/utils)
+set(TRANSPORT_HTTP ${TRANSPORT_ROOT_PATH}/http)
+set(TRANSPORT_PORTABILITY ${TRANSPORT_ROOT_PATH}/portability)
+set(TRANSPORT_INTERFACES ${TRANSPORT_ROOT_PATH}/interfaces)
+
+set(raaqm_config_path ${CMAKE_INSTALL_PREFIX}/etc/hicn-consumer.conf)
+
+# Install includes
+set(INSTALL_INCLUDE_DIR include/hicn/transport)
+
+if ((BUILD_MEMIF_CONNECTOR OR BUILD_VPP_PLUGIN) AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ set(__vpp__ 1)
+ find_package(Vpp REQUIRED)
+ find_package(Libmemif REQUIRED)
+ list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+ ${VPP_INCLUDE_DIRS}
+ ${LIBMEMIF_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIBRARIES
+ # ${VPP_INCLUDE_DIRS}
+ ${LIBMEMIF_LIBRARIES}
+ )
+endif ()
+
+include(IosMacros)
+find_package_wrapper(Libparc REQUIRED)
+find_package_wrapper(Asio REQUIRED)
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package_wrapper(Libhicn REQUIRED)
+ if (__vpp__)
+ find_package_wrapper(HicnBinaryApi REQUIRED)
+ endif()
+ set(LIBTRANSPORT transport)
+else()
+ set(HICN_LIBRARIES ${LIBHICN_SHARED})
+ list(APPEND DEPENDENCIES
+ ${LIBHICN}
+ ${LIBHICN_SHARED}
+ )
+
+ if (__vpp__)
+ list(APPEND DEPENDENCIES
+ hicn_plugin
+ )
+ endif()
+endif()
+
+find_package(Threads REQUIRED)
+
+if (${COMPILE_TESTS})
+ include(TestMacros)
+ find_package(GTest REQUIRED)
+ list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+ ${GTEST_INCLUDE_DIRS}
+ )
+endif()
+
+list(APPEND LIBRARIES
+ ${LIBPARC_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${HICN_LIBRARIES}
+ ${VPP_LIBRARIES}
+ ${ANDROID_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+)
+
+# Include dirs -- Order does matter!
+list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+ ${HICN_INCLUDE_DIRS}
+ ${HICN_BINARY_API_INCLUDE_DIRS}
+ ${LIBPARC_INCLUDE_DIRS}
+ ${CMAKE_THREADS_INCLUDE_DIRS}
+ ${ASIO_INCLUDE_DIRS}
+)
+
+add_subdirectory(${TRANSPORT_ROOT_PATH})
+
+# Packaging
+add_package(libtransport
+ NAME "libtransport"
+ # DEPENDENCIES "fd.io" FIXME
+ DESCRIPTION "Shared Memory Interface"
+)
diff --git a/libtransport/README.md b/libtransport/README.md
new file mode 100755
index 000000000..e7fc267ee
--- /dev/null
+++ b/libtransport/README.md
@@ -0,0 +1,126 @@
+Libtransport: data transport library for hICN
+====================================================
+
+## Introduction ##
+
+This library provides transport services and socket API for applications willing to communicate
+using the hICN protocol stack.
+
+Overview:
+
+- Implementation of the hICN core objects (interest, data, name..) exploiting the API provided by [libhicn](../lib).
+- Connectors for connecting the application to either the hicn-plugin or the hicn-light forwarder.
+- Transport protocols (RAAQM, CBR, RTP)
+- Transport services (authentication, integrity, segmentation, reassembly, naming)
+- Interfaces for Applications (from low-level interfaces for interest-data interaction to high level interfaces for Application Data Unit interaction)
+
+## Build Dependencies ##
+
+- libparc
+- libmemif (linux only, if compiling with VPP support)
+- libasio
+
+### Ubuntu 16.04 and Ubuntu 18.04 ###
+
+```bash
+ $ echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io.master.ubuntu.$(lsb_release -sc).main/ ./" \
+ | sudo tee -a /etc/apt/sources.list.d/99fd.io.list
+ $ sudo apt-get install libparc libasio-dev
+```
+
+If you wish to use the library for connecting to the vpp hicn-plugin, you will need to also install vpp, the vpp libraries and the libmemif libraries:
+
+- DEB packages:
+ - vpp
+ - vpp-lib
+ - vpp-dev
+
+You can get them either from from the vpp packages ot the source code. Check the [VPP wiki](https://wiki.fd.io/view/VPP) for instructions.
+
+Libmemif is in the vpp-lib and vpp-dev packages.
+
+### Mac OSX ###
+
+We recommend to use [HomeBrew](https://brew.sh/) for installing the libasio dependency:
+
+```bash
+ $ brew install asio
+```
+
+Download, compile and install libparc:
+
+```bash
+ $ git clone -b cframework/master https://gerrit.fd.io/r/cicn cframework && cd cframework
+ $ mkdir -p libparc.build && cd libparc.build
+ $ cmake ../libparc
+ $ make
+ $ make install
+```
+
+Libparc will be installed by default under `/usr/local/lib` and `/usr/local/include`.
+
+Since VPP does not support MAC OS, the hicn-plugin connector is not built.
+
+## Build The library ##
+
+From the project root folder:
+
+```bash
+ $ cd libtransport
+ $ mkdir build && cd build
+ $ cmake ..
+ $ make
+```
+### Compile options ###
+
+The build process can be customized with the following options:
+
+- `CMAKE_INSTALL_PREFIX`: The path where you want to install the library.
+- `CMAKE_BUILD_TYPE`: The build configuration. Options: `Release`, `Debug`. Default is `Release`.
+- `ASIO_HOME`: The folder containing the libasio headers.
+- `LIBPARC_HOME`: The folder containing the libparc headers and libraries.
+- `VPP_HOME`: The folder containing the installation of VPP.
+- `LIBMEMIF_HOME`: The folder containing the libmemif headers and libraries.
+- `BUILD_MEMIF_CONNECTOR`: On linux, set this value to `ON` for building the VPP connector.
+
+An option can be set using cmake -D`OPTION`=`VALUE`.
+
+Install the library
+-------------------
+
+For installing the library, from the cmake build folder:
+
+```bash
+ $ sudo make install
+```
+
+## Supported platforms
+
+- Ubuntu 16.04 LTS (x86_64)
+- Ubuntu 18.04 LTS (x86_64)
+- Debian Stable/Testing
+- Red Hat Enterprise Linux 7
+- CentOS 7
+- Android 8
+- iOS 12
+- macOS 10.12
+- Windows 10
+
+## License ##
+
+This software is distributed under the following license:
+
+```
+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.
+``` \ No newline at end of file
diff --git a/libtransport/cmake/Modules/Android.cmake b/libtransport/cmake/Modules/Android.cmake
new file mode 100755
index 000000000..78918455a
--- /dev/null
+++ b/libtransport/cmake/Modules/Android.cmake
@@ -0,0 +1,19 @@
+# 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.
+
+function (configure_android_environment)
+ set(CMAKE_CXX_FLAGS " -Wall -stdlib=libc++ -DASIO_STANDALONE -pthread -isystem -lm")
+
+ #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
+ #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}" PARENT_SCOPE)
+endfunction() \ No newline at end of file
diff --git a/libtransport/cmake/Modules/DefaultConfiguration.cmake b/libtransport/cmake/Modules/DefaultConfiguration.cmake
new file mode 100755
index 000000000..2110ac0fb
--- /dev/null
+++ b/libtransport/cmake/Modules/DefaultConfiguration.cmake
@@ -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.
+
+# C/c++ standard
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_C_STANDARD 11)
+
+# Compilation options
+option(BUILD_APPS "Build apps" ON)
+option(BUILD_WITH_VPP "Add support for VPP" OFF)
+option(COMPILE_TESTS "Compile functional tests" OFF)
+
+# Compilation flags
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fpermissive")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fpermissive")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -fpermissive")
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
+
+# Packaging
+# TODO Libasio and libmemif
+set(DEPS_DEB "libparc (>= 1.0)")
+set(DEPS_RPM "libparc >= 1.0")
+set(BUILD_DEPS_DEB "libtransport (>= 1.0), libhicn-dev (>= 1.0), libparc-dev (>= 1.0)")
+set(BUILD_DEPS_RPM "libtransport >= 1.0, libhicn-devel >= 1.0, libparc-devel >= 1.0")
+
+set(VPP_DEPS_DEB "${DEPS_DEB}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+set(VPP_DEPS_RPM "${DEPS_RPM}, hicn-plugin, vpp-lib >= 18.07), vpp-dev (>= 18.07)")
+set(VPP_BUILD_DEPS_DEB "${BUILD_DEPS_DEB}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+set(VPP_BUILD_DEPS_RPM "${BUILD_DEPS_RPM}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+
+set(PACKAGE_DESCRIPTION "This library is designed to provide a transport layer and API for applications willing to communicate using an hICN protocol stack.")
+set(PACKAGE_HOMEPAGE "https://wiki.fd.io/view/Libicnet") \ No newline at end of file
diff --git a/libtransport/cmake/Modules/Ios.cmake b/libtransport/cmake/Modules/Ios.cmake
new file mode 100755
index 000000000..a4e625e98
--- /dev/null
+++ b/libtransport/cmake/Modules/Ios.cmake
@@ -0,0 +1,23 @@
+# 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.
+
+function (configure_ios_environment)
+ find_host_package ( OpenSSL REQUIRED )
+ include_directories(extras/iOS)
+
+ find_host_package(Libparc REQUIRED)
+ include_directories(${LIBPARC_INCLUDE_DIRS})
+
+ find_host_package(Libhicn REQUIRED)
+ include_directories(${HICN_INCLUDE_DIRS})
+endfunction() \ No newline at end of file
diff --git a/libtransport/cmake/Modules/Packager.cmake b/libtransport/cmake/Modules/Packager.cmake
new file mode 100755
index 000000000..019f18c4e
--- /dev/null
+++ b/libtransport/cmake/Modules/Packager.cmake
@@ -0,0 +1,197 @@
+# 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.
+
+# Generate DEB / RPM packages
+
+# Default variables
+
+if (NOT DEFINED ENV{VENDOR})
+ set(VENDOR "Cisco Systems" CACHE STRING "Vendor")
+else ()
+ set(VENDOR ENV{VENDOR} CACHE STRING "Vendor")
+endif ()
+
+if (NOT DEFINED ENV{CONTACT})
+ set(CONTACT "msardara@cisco.com" CACHE STRING "Contact")
+else ()
+ set(CONTACT ENV{CONTACT} CACHE STRING "Contact")
+endif()
+
+if (NOT DEFINED ENV{PACKAGE_MAINTAINER})
+ set(PACKAGE_MAINTAINER "Mauro Sardara (msardara@cisco.com)" CACHE STRING "Maintainer")
+else ()
+ set(PACKAGE_MAINTAINER ENV{PACKAGE_MAINTAINER} CACHE STRING "Maintainer")
+endif()
+
+if (NOT DEFINED ENV{CPACK_PACKAGING_INSTALL_PREFIX})
+ set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+else ()
+ set(CPACK_PACKAGING_INSTALL_PREFIX ENV{CPACK_PACKAGING_INSTALL_PREFIX})
+endif()
+
+set(CPACK_COMPONENTS_ALL library headers utils documentation)
+
+function (make_package_internal PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE GENERATOR TYPE DESCRIPTION HOMEPAGE)
+ set(CPACK_GENERATOR ${GENERATOR})
+ set(CPACK_PACKAGE_VENDOR ${VENDOR})
+ set(CPACK_PACKAGE_CONTACT ${CONTACT})
+
+ set(CPACK_${GENERATOR}_COMPONENT_INSTALL ON)
+ set(CPACK_${TYPE}_PACKAGE_MAINTAINER ${PACKAGE_MAINTAINER})
+ set(CPACK_${TYPE}_PACKAGE_NAME ${PACKAGE_NAME})
+ set(CPACK_${TYPE}_PACKAGE_VERSION ${PACKAGE_VERSION})
+ set(CPACK_${TYPE}_PACKAGE_ARCHITECTURE ${ARCHITECTURE})
+ set(CPACK_${TYPE}_PACKAGE_RELEASE 1)
+ set(CPACK_${TYPE}_PACKAGE_VENDOR ${VENDOR})
+ set(CPACK_${TYPE}_PACKAGE_DESCRIPTION ${DESCRIPTION})
+ set(CPACK_${TYPE}_PACKAGE_HOMEPAGE ${HOMEPAGE})
+
+ include(CPack)
+endfunction()
+
+function(make_deb_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE DEPS BUILD_DEPS DESCRIPTION HOMEPAGE)
+
+ set(TYPE "DEBIAN")
+ set(GENERATOR "DEB")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_UTILS_PACKAGE_NAME "${PACKAGE_NAME}-utils")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-dev")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_UTILS_FILE_NAME "${CPACK_${TYPE}_UTILS_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${CPACK_${TYPE}_HEADERS_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+
+ set(CPACK_DEBIAN_LIBRARY_PACKAGE_SHLIBDEPS OFF)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_DEPENDS ${DEPS})
+ set(CPACK_${TYPE}_UTILS_PACKAGE_DEPENDS ${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME})
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_DEPENDS ${BUILD_DEPS})
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_DEPENDS "")
+
+ make_package_internal(${PACKAGE_NAME} ${PACKAGE_VERSION} ${ARCHITECTURE} ${GENERATOR} ${TYPE} ${DESCRIPTION} ${HOMEPAGE})
+endfunction()
+
+function(make_rpm_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE DEPS BUILD_DEPS DESCRIPTION HOMEPAGE)
+ set(TYPE "RPM")
+ set(GENERATOR "RPM")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_UTILS_PACKAGE_NAME "${PACKAGE_NAME}-utils")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-devel")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_UTILS_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${CPACK_${TYPE}_HEADERS_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_AUTOREQ OFF)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_REQUIRES ${DEPS})
+ set(CPACK_${TYPE}_UTILS_PACKAGE_DEPENDS ${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME})
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_REQUIRES ${BUILD_DEPS})
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_REQUIRES "")
+
+ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/etc" "/usr/lib/python2.7" "/usr/lib/python2.7/site-packages")
+
+ make_package_internal(${PACKAGE_NAME} ${PACKAGE_VERSION} ${ARCHITECTURE} ${GENERATOR} ${TYPE} ${DESCRIPTION} ${HOMEPAGE})
+endfunction()
+
+function(make_tgz_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE)
+
+ set(TYPE "ARCHIVE")
+ set(GENERATOR "TGZ")
+
+ set(CPACK_${TYPE}_COMPONENT_INSTALL ON)
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}")
+ set(CPACK_${TYPE}_UTILS_FILE_NAME "${PACKAGE_NAME}-utils_${PACKAGE_VERSION}_${ARCHITECTURE}")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-dev_${PACKAGE_VERSION}_${ARCHITECTURE}")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc_${PACKAGE_VERSION}_${ARCHITECTURE}")
+
+ set(CPACK_GENERATOR ${GENERATOR})
+ set(CPACK_PACKAGE_VENDOR ${VENDOR})
+ set(CPACK_PACKAGE_CONTACT ${CONTACT})
+
+ include(CPack)
+
+endfunction()
+
+function (make_package DEPS_DEB DEPS_RPM BUILD_DEPS_DEB BUILD_DEPS_RPM DESCRIPTION HOMEPAGE)
+
+ if (NOT DEFINED ENV{PACKAGE_NAME})
+ string(TOLOWER ${CMAKE_PROJECT_NAME} PACKAGE_NAME)
+ else ()
+ string(TOLOWER $ENV{PACKAGE_NAME} PACKAGE_NAME)
+ endif ()
+
+ # Get the version
+ execute_process(COMMAND bash ${CMAKE_SOURCE_DIR}/scripts/version
+ OUTPUT_VARIABLE PACKAGE_VERSION)
+
+ if (PACKAGE_VERSION)
+ string(STRIP ${PACKAGE_VERSION} PACKAGE_VERSION)
+ else ()
+ set(PACKAGE_VERSION 1.0)
+ endif ()
+
+ if (EXISTS "/etc/lsb-release")
+ execute_process(COMMAND grep -oP "(?<=DISTRIB_ID=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_ID)
+ execute_process(COMMAND grep -oP "(?<=DISTRIB_RELEASE=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_RELEASE)
+ execute_process(COMMAND grep -oP "(?<=DISTRIB_CODENAME=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_CODENAME)
+ execute_process(COMMAND grep -oP "(?<=DISTRIB_DESCRIPTION=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_DESCRIPTION)
+ execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+ if (${ARCHITECTURE} STREQUAL "x86_64")
+ set(ARCHITECTURE "amd64")
+ endif()
+
+ make_deb_package(${PACKAGE_NAME}
+ ${PACKAGE_VERSION}
+ ${ARCHITECTURE}
+ ${DEPS_DEB}
+ ${BUILD_DEPS_DEB}
+ ${DESCRIPTION}
+ ${HOMEPAGE})
+
+ elseif(EXISTS "/etc/redhat-release")
+ execute_process(COMMAND sudo yum install -y redhat-lsb)
+ execute_process(COMMAND lsb_release -si OUTPUT_VARIABLE DISTRIB_ID)
+ execute_process(COMMAND lsb_release -sr OUTPUT_VARIABLE DISTRIB_RELEASE)
+ execute_process(COMMAND lsb_release -sc OUTPUT_VARIABLE DISTRIB_CODENAME)
+ execute_process(COMMAND lsb_release -sd OUTPUT_VARIABLE DISTRIB_DESCRIPTION)
+ execute_process(COMMAND uname -m -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+ make_rpm_package(${PACKAGE_NAME}
+ ${PACKAGE_VERSION}
+ ${ARCHITECTURE}
+ ${DEPS_RPM}
+ ${BUILD_DEPS_RPM}
+ ${DESCRIPTION}
+ ${HOMEPAGE})
+ else()
+ execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+ if (${ARCHITECTURE} STREQUAL "x86_64")
+ set(ARCHITECTURE "amd64")
+ endif()
+
+ # Other linux system. Create a tar.gz package
+ make_tgz_package(${PACKAGE_NAME}
+ ${PACKAGE_VERSION}
+ ${ARCHITECTURE})
+
+ endif()
+endfunction()
diff --git a/libtransport/cmake/Modules/TestMacros.cmake b/libtransport/cmake/Modules/TestMacros.cmake
new file mode 100755
index 000000000..680b5585f
--- /dev/null
+++ b/libtransport/cmake/Modules/TestMacros.cmake
@@ -0,0 +1,15 @@
+# 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(CTest)
+
diff --git a/libtransport/src/hicn/transport/CMakeLists.txt b/libtransport/src/hicn/transport/CMakeLists.txt
new file mode 100755
index 000000000..f3c1cd2dc
--- /dev/null
+++ b/libtransport/src/hicn/transport/CMakeLists.txt
@@ -0,0 +1,54 @@
+# 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)
+
+configure_file("config.h.in" "config.h" @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h DESTINATION include/hicn/transport COMPONENT libtransport-dev)
+
+add_subdirectory(core)
+add_subdirectory(errors)
+add_subdirectory(http)
+add_subdirectory(interfaces)
+add_subdirectory(portability)
+add_subdirectory(protocols)
+add_subdirectory(utils)
+
+set (COMPILER_DEFINITIONS "-DASIO_STANDALONE")
+
+list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/../..
+ ${CMAKE_CURRENT_BINARY_DIR}/../..
+)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
+if (ANDROID_API)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm")
+endif()
+
+build_library(${LIBTRANSPORT}
+ STATIC SHARED
+ SOURCES ${SOURCE_FILES}
+ INSTALL_HEADERS ${HEADER_FILES}
+ LINK_LIBRARIES ${LIBRARIES}
+ DEPENDS ${DEPENDENCIES}
+ COMPONENT libtransport
+ INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS}
+ INSTALL_ROOT_DIR hicn/transport
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+)
+
+if (${COMPILE_TESTS})
+ add_subdirectory(core/test)
+ add_subdirectory(transport/test)
+endif() \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/config.h.in b/libtransport/src/hicn/transport/config.h.in
new file mode 100755
index 000000000..a140f4b78
--- /dev/null
+++ b/libtransport/src/hicn/transport/config.h.in
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+#cmakedefine TRANSPORT_HAVE_PTHREAD 1
+
+#define RAAQM_CONFIG_PATH "@raaqm_config_path@"
+
+#cmakedefine __vpp__
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
diff --git a/libtransport/src/hicn/transport/errors/CMakeLists.txt b/libtransport/src/hicn/transport/errors/CMakeLists.txt
new file mode 100755
index 000000000..1c19a9070
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/CMakeLists.txt
@@ -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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/not_implemented_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/invalid_ip_address_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/malformed_name_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/errors.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/malformed_packet_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/runtime_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/null_pointer_exception.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/malformed_ahpacket_exception.h
+)
+
+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/errors/errors.h b/libtransport/src/hicn/transport/errors/errors.h
new file mode 100755
index 000000000..512e35736
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/errors.h
@@ -0,0 +1,24 @@
+/*
+ * 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/errors/invalid_ip_address_exception.h>
+#include <hicn/transport/errors/malformed_name_exception.h>
+#include <hicn/transport/errors/malformed_packet_exception.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <hicn/transport/errors/null_pointer_exception.h>
+#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/errors/tokenizer_exception.h> \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h
new file mode 100755
index 000000000..60226f576
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class InvalidIpAddressException : public std::runtime_error {
+ public:
+ InvalidIpAddressException() : std::runtime_error("") {}
+
+ virtual char const *what() const noexcept override {
+ return "Malformed IP address.";
+ }
+};
+
+} // end namespace errors \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h
new file mode 100755
index 000000000..f0cfe0b82
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class MalformedAHPacketException : public std::runtime_error {
+ public:
+ MalformedAHPacketException() : std::runtime_error("") {}
+
+ virtual char const *what() const noexcept override {
+ return "Malformed AH packet.";
+ }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/malformed_name_exception.h b/libtransport/src/hicn/transport/errors/malformed_name_exception.h
new file mode 100755
index 000000000..4ef45d2e8
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/malformed_name_exception.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class MalformedNameException : public std::runtime_error {
+ public:
+ MalformedNameException() : std::runtime_error("") {}
+
+ virtual char const *what() const noexcept override {
+ return "Malformed IP address.";
+ }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/malformed_packet_exception.h b/libtransport/src/hicn/transport/errors/malformed_packet_exception.h
new file mode 100755
index 000000000..ec5c97e6e
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/malformed_packet_exception.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
+
+#include <stdexcept>
+
+namespace errors {
+
+class MalformedPacketException : public std::runtime_error {
+ public:
+ MalformedPacketException() : std::runtime_error("") {}
+
+ char const *what() const noexcept override { return "Malformed IP packet."; }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/not_implemented_exception.h b/libtransport/src/hicn/transport/errors/not_implemented_exception.h
new file mode 100755
index 000000000..e9869163d
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/not_implemented_exception.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class NotImplementedException : public std::logic_error {
+ public:
+ NotImplementedException() : std::logic_error("") {}
+ virtual char const *what() const noexcept override {
+ return "Function not yet implemented.";
+ }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/null_pointer_exception.h b/libtransport/src/hicn/transport/errors/null_pointer_exception.h
new file mode 100755
index 000000000..bd06485ed
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/null_pointer_exception.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class NullPointerException : public std::runtime_error {
+ public:
+ NullPointerException() : std::runtime_error("") {}
+
+ char const *what() const noexcept override {
+ return "Null pointer exception.";
+ }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/runtime_exception.h b/libtransport/src/hicn/transport/errors/runtime_exception.h
new file mode 100755
index 000000000..ba5128a7e
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/runtime_exception.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+namespace errors {
+
+class RuntimeException : public std::runtime_error {
+ public:
+ RuntimeException() : std::runtime_error("") {}
+
+ RuntimeException(std::string what) : runtime_error(what){};
+};
+
+} // end namespace errors \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/tokenizer_exception.h b/libtransport/src/hicn/transport/errors/tokenizer_exception.h
new file mode 100755
index 000000000..76eda838e
--- /dev/null
+++ b/libtransport/src/hicn/transport/errors/tokenizer_exception.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdexcept>
+
+namespace errors {
+
+class TokenizerException : public std::logic_error {
+ public:
+ TokenizerException() : std::logic_error("") {}
+
+ virtual char const *what() const noexcept override {
+ return "No more tokens available.";
+ }
+};
+
+} // end namespace errors
diff --git a/libtransport/src/hicn/transport/http/CMakeLists.txt b/libtransport/src/hicn/transport/http/CMakeLists.txt
new file mode 100755
index 000000000..ddcf1fdc3
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/CMakeLists.txt
@@ -0,0 +1,36 @@
+# 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 SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/request.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/response.cc)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/request.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/default_values.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/facade.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/response.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/message.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.h
+)
+
+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/http/callbacks.h b/libtransport/src/hicn/transport/http/callbacks.h
new file mode 100755
index 000000000..5ca5fcbe2
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/callbacks.h
@@ -0,0 +1,46 @@
+/*
+ * 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/http/server_publisher.h>
+
+#include <functional>
+#include <memory>
+
+namespace transport {
+
+namespace http {
+
+enum class RC : uint8_t {
+ SUCCESS,
+ CONTENT_PUBLISHED,
+ ERR_UNDEFINED,
+};
+
+using OnHttpRequest =
+ std::function<void(std::shared_ptr<HTTPServerPublisher>&, const uint8_t*,
+ std::size_t, int request_id)>;
+using DeadlineTimerCallback = std::function<void(const std::error_code& e)>;
+using ReceiveCallback = std::function<void(const std::vector<uint8_t>&)>;
+using OnPayloadCallback = std::function<RC(
+ const std::error_code& ec, const core::Name& name,
+ const std::shared_ptr<utils::SharableVector<uint8_t>>& payload)>;
+using ContentSentCallback =
+ std::function<void(const std::error_code&, const core::Name&)>;
+
+} // namespace http
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/client_connection.cc b/libtransport/src/hicn/transport/http/client_connection.cc
new file mode 100755
index 000000000..d4207bb81
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/client_connection.cc
@@ -0,0 +1,194 @@
+/*
+ * 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/http/client_connection.h>
+#include <hicn/transport/utils/hash.h>
+
+#define DEFAULT_BETA 0.99
+#define DEFAULT_GAMMA 0.07
+
+namespace transport {
+
+namespace http {
+
+using namespace transport;
+
+HTTPClientConnection::HTTPClientConnection()
+ : consumer_(TransportProtocolAlgorithms::RAAQM, io_service_),
+ response_(std::make_shared<HTTPResponse>()),
+ timer_(nullptr) {
+ consumer_.setSocketOption(
+ ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
+ (ConsumerContentObjectVerificationCallback)std::bind(
+ &HTTPClientConnection::verifyData, this, std::placeholders::_1,
+ std::placeholders::_2));
+
+ consumer_.setSocketOption(
+ ConsumerCallbacksOptions::CONTENT_RETRIEVED,
+ (ConsumerContentCallback)std::bind(
+ &HTTPClientConnection::processPayload, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3));
+
+ consumer_.connect();
+ std::shared_ptr<typename ConsumerSocket::Portal> portal;
+ consumer_.getSocketOption(GeneralTransportOptions::PORTAL, portal);
+ timer_ = std::make_unique<asio::steady_timer>(portal->getIoService());
+}
+
+HTTPClientConnection &HTTPClientConnection::get(
+ const std::string &url, HTTPHeaders headers, HTTPPayload payload,
+ std::shared_ptr<HTTPResponse> response) {
+ return sendRequest(url, HTTPMethod::GET, headers, payload, response);
+}
+
+HTTPClientConnection &HTTPClientConnection::sendRequest(
+ const std::string &url, HTTPMethod method, HTTPHeaders headers,
+ HTTPPayload payload, std::shared_ptr<HTTPResponse> response) {
+ if (!response) {
+ response = response_;
+ }
+
+ auto start = std::chrono::steady_clock::now();
+ HTTPRequest request(method, url, headers, payload);
+ std::string name = sendRequestGetReply(request, response);
+ auto end = std::chrono::steady_clock::now();
+
+ TRANSPORT_LOGI(
+ "%s %s [%s] duration: %llu [usec] %zu [bytes]\n",
+ method_map[method].c_str(), url.c_str(), name.c_str(),
+ (unsigned long long)std::chrono::duration_cast<std::chrono::microseconds>(
+ end - start)
+ .count(),
+ response->size());
+
+ return *this;
+}
+
+std::string HTTPClientConnection::sendRequestGetReply(
+ const HTTPRequest &request, std::shared_ptr<HTTPResponse> &response) {
+ const std::string &request_string = request.getRequestString();
+ const std::string &locator = request.getLocator();
+
+ // Hash it
+
+ uint32_t locator_hash =
+ utils::hash::fnv32_buf(locator.c_str(), locator.size());
+ uint64_t request_hash =
+ utils::hash::fnv64_buf(request_string.c_str(), request_string.size());
+
+ consumer_.setSocketOption(
+ ConsumerCallbacksOptions::INTEREST_OUTPUT,
+ (ConsumerInterestCallback)std::bind(
+ &HTTPClientConnection::processLeavingInterest, this,
+ std::placeholders::_1, std::placeholders::_2, request_string));
+
+ // Send content to producer piggybacking it through first interest (to fix)
+
+ response->clear();
+
+ // Factor hicn name using hash
+
+ std::stringstream stream;
+
+ stream << std::hex << http::default_values::ipv6_first_word << ":";
+
+ for (uint16_t *word = (uint16_t *)&locator_hash;
+ std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash));
+ word++) {
+ stream << ":" << std::hex << *word;
+ }
+
+ for (uint16_t *word = (uint16_t *)&request_hash;
+ std::size_t(word) < (std::size_t(&request_hash) + sizeof(request_hash));
+ word++) {
+ stream << ":" << std::hex << *word;
+ }
+
+ stream << "|0";
+
+ consumer_.consume(Name(stream.str()), *response);
+
+ consumer_.stop();
+
+ return stream.str();
+}
+
+HTTPResponse &&HTTPClientConnection::response() {
+ // response_->parse();
+ return std::move(*response_);
+}
+
+void HTTPClientConnection::processPayload(ConsumerSocket &c,
+ std::size_t bytes_transferred,
+ const std::error_code &ec) {
+ if (ec) {
+ TRANSPORT_LOGE("Download failed!!");
+ }
+}
+
+bool HTTPClientConnection::verifyData(
+ ConsumerSocket &c, const core::ContentObject &contentObject) {
+ if (contentObject.getPayloadType() == PayloadType::CONTENT_OBJECT) {
+ TRANSPORT_LOGI("VERIFY CONTENT\n");
+ } else if (contentObject.getPayloadType() == PayloadType::MANIFEST) {
+ TRANSPORT_LOGI("VERIFY MANIFEST\n");
+ }
+
+ return true;
+}
+
+void HTTPClientConnection::processLeavingInterest(
+ ConsumerSocket &c, const core::Interest &interest, std::string &payload) {
+ // if (interest.getName().getSuffix() == 0) {
+ Interest &int2 = const_cast<Interest &>(interest);
+ int2.appendPayload((uint8_t *)payload.data(), payload.size());
+ // }
+}
+
+ConsumerSocket &HTTPClientConnection::getConsumer() { return consumer_; }
+
+HTTPClientConnection &HTTPClientConnection::stop() {
+ // This is thread safe and can be called from another thread
+ consumer_.stop();
+
+ return *this;
+}
+
+HTTPClientConnection &HTTPClientConnection::setTimeout(
+ const std::chrono::seconds &timeout) {
+ timer_->cancel();
+ timer_->expires_from_now(timeout);
+ timer_->async_wait([this](std::error_code ec) {
+ if (!ec) {
+ consumer_.stop();
+ }
+ });
+
+ return *this;
+}
+
+HTTPClientConnection &HTTPClientConnection::setCertificate(
+ const std::string &cert_path) {
+ if (consumer_.setSocketOption(GeneralTransportOptions::CERTIFICATE,
+ cert_path) == SOCKET_OPTION_NOT_SET) {
+ throw errors::RuntimeException("Error setting the certificate.");
+ }
+
+ return *this;
+}
+
+} // namespace http
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/http/client_connection.h b/libtransport/src/hicn/transport/http/client_connection.h
new file mode 100755
index 000000000..f6e1fa03e
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/client_connection.h
@@ -0,0 +1,82 @@
+/*
+ * 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/http/default_values.h>
+#include <hicn/transport/http/request.h>
+#include <hicn/transport/http/response.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/utils/uri.h>
+
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+using namespace interface;
+using namespace core;
+
+class HTTPClientConnection {
+ public:
+ HTTPClientConnection();
+
+ HTTPClientConnection &get(const std::string &url, HTTPHeaders headers = {},
+ HTTPPayload payload = {},
+ std::shared_ptr<HTTPResponse> response = nullptr);
+
+ HTTPClientConnection &sendRequest(
+ const std::string &url, HTTPMethod method, HTTPHeaders headers = {},
+ HTTPPayload payload = {},
+ std::shared_ptr<HTTPResponse> response = nullptr);
+
+ HTTPResponse &&response();
+
+ HTTPClientConnection &stop();
+
+ interface::ConsumerSocket &getConsumer();
+
+ HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout);
+
+ HTTPClientConnection &setCertificate(const std::string &cert_path);
+
+ private:
+ void processPayload(interface::ConsumerSocket &c,
+ std::size_t bytes_transferred, const std::error_code &ec);
+
+ std::string sendRequestGetReply(const HTTPRequest &request,
+ std::shared_ptr<HTTPResponse> &response);
+
+ bool verifyData(interface::ConsumerSocket &c,
+ const core::ContentObject &contentObject);
+
+ void processLeavingInterest(interface::ConsumerSocket &c,
+ const core::Interest &interest,
+ std::string &payload);
+
+ asio::io_service io_service_;
+
+ ConsumerSocket consumer_;
+
+ std::shared_ptr<HTTPResponse> response_;
+
+ std::unique_ptr<asio::steady_timer> timer_;
+};
+
+} // end namespace http
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/default_values.h b/libtransport/src/hicn/transport/http/default_values.h
new file mode 100755
index 000000000..2d5a6b821
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/default_values.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <cstdint>
+
+namespace transport {
+
+namespace http {
+
+namespace default_values {
+
+const uint16_t ipv6_first_word = 0xb001; // Network byte order
+
+} // namespace default_values
+
+} // namespace http
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/http/facade.h b/libtransport/src/hicn/transport/http/facade.h
new file mode 100755
index 000000000..31c2d1b8d
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/facade.h
@@ -0,0 +1,22 @@
+/*
+ * 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/http/transport_http_client_connection.h>
+#include <hicn/transport/http/transport_http_server_acceptor.h>
+#include <hicn/transport/http/transport_http_server_publisher.h>
+
+namespace libl4 = transport; \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/message.h b/libtransport/src/hicn/transport/http/message.h
new file mode 100755
index 000000000..7d4485c90
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/message.h
@@ -0,0 +1,58 @@
+/*
+ * 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/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+#define HTTP_VERSION "1.1"
+
+namespace transport {
+
+namespace http {
+
+typedef enum { GET, POST, PUT, PATCH, DELETE } HTTPMethod;
+
+static std::map<HTTPMethod, std::string> method_map = {
+ {GET, "GET"}, {POST, "POST"}, {PUT, "PUT"},
+ {PATCH, "PATCH"}, {DELETE, "DELETE"},
+};
+
+typedef std::map<std::string, std::string> HTTPHeaders;
+typedef std::vector<uint8_t> HTTPPayload;
+
+class HTTPMessage {
+ public:
+ virtual ~HTTPMessage() = default;
+
+ virtual const HTTPHeaders &getHeaders() = 0;
+
+ virtual const HTTPPayload &getPayload() = 0;
+
+ virtual const std::string &getHttpVersion() const = 0;
+
+ protected:
+ HTTPHeaders headers_;
+ HTTPPayload payload_;
+ std::string http_version_;
+};
+
+} // end namespace http
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/request.cc b/libtransport/src/hicn/transport/http/request.cc
new file mode 100755
index 000000000..7a63b4f75
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/request.cc
@@ -0,0 +1,83 @@
+/*
+ * 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/http/request.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace transport {
+
+namespace http {
+
+// std::map<HTTPMethod, std::string> method_map
+
+HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url,
+ const HTTPHeaders &headers,
+ const HTTPPayload &payload) {
+ utils::Uri uri;
+ uri.parse(url);
+
+ path_ = uri.getPath();
+ query_string_ = uri.getQueryString();
+ protocol_ = uri.getProtocol();
+ locator_ = uri.getLocator();
+ port_ = uri.getPort();
+ http_version_ = HTTP_VERSION;
+
+ headers_ = headers;
+ payload_ = payload;
+
+ std::transform(locator_.begin(), locator_.end(), locator_.begin(), ::tolower);
+
+ std::transform(protocol_.begin(), protocol_.end(), protocol_.begin(),
+ ::tolower);
+
+ std::stringstream stream;
+ stream << method_map[method] << " " << uri.getPath() << " HTTP/"
+ << HTTP_VERSION << "\r\n";
+ for (auto &item : headers) {
+ stream << item.first << ": " << item.second << "\r\n";
+ }
+ stream << "\r\n";
+
+ if (payload.size() > 0) {
+ stream << payload.data();
+ }
+
+ request_string_ = stream.str();
+}
+
+const std::string &HTTPRequest::getPort() const { return port_; }
+
+const std::string &HTTPRequest::getLocator() const { return locator_; }
+
+const std::string &HTTPRequest::getProtocol() const { return protocol_; }
+
+const std::string &HTTPRequest::getPath() const { return path_; }
+
+const std::string &HTTPRequest::getQueryString() const { return query_string_; }
+
+const HTTPHeaders &HTTPRequest::getHeaders() { return headers_; }
+
+const HTTPPayload &HTTPRequest::getPayload() { return payload_; }
+
+const std::string &HTTPRequest::getRequestString() const {
+ return request_string_;
+}
+
+const std::string &HTTPRequest::getHttpVersion() const { return http_version_; }
+
+} // namespace http
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/request.h b/libtransport/src/hicn/transport/http/request.h
new file mode 100755
index 000000000..88d67d4ad
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/request.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/http/message.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPRequest : public HTTPMessage {
+ public:
+ HTTPRequest(HTTPMethod method, const std::string &url,
+ const HTTPHeaders &headers, const HTTPPayload &payload);
+
+ const std::string &getQueryString() const;
+
+ const std::string &getPath() const;
+
+ const std::string &getProtocol() const;
+
+ const std::string &getLocator() const;
+
+ const std::string &getPort() const;
+
+ const std::string &getRequestString() const;
+
+ const HTTPHeaders &getHeaders() override;
+
+ const HTTPPayload &getPayload() override;
+
+ const std::string &getHttpVersion() const override;
+
+ private:
+ std::string query_string_, path_, protocol_, locator_, port_;
+ std::string request_string_;
+ HTTPHeaders headers_;
+ HTTPPayload payload_;
+};
+
+} // end namespace http
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/response.cc b/libtransport/src/hicn/transport/http/response.cc
new file mode 100755
index 000000000..0aa9affe8
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/response.cc
@@ -0,0 +1,134 @@
+/*
+ * 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/errors/errors.h>
+#include <hicn/transport/http/response.h>
+
+#include <algorithm>
+
+#include <cstring>
+
+namespace transport {
+
+namespace http {
+
+HTTPResponse::HTTPResponse() {}
+
+HTTPResponse::HTTPResponse(const HTTPHeaders &headers,
+ const HTTPPayload &payload) {
+ headers_ = headers;
+ payload_ = payload;
+}
+
+const HTTPHeaders &HTTPResponse::getHeaders() {
+ parse();
+ return headers_;
+}
+
+const HTTPPayload &HTTPResponse::getPayload() {
+ parse();
+ return payload_;
+}
+
+bool HTTPResponse::parseHeaders() {
+ const char *crlf2 = "\r\n\r\n";
+ auto it =
+ std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+ if (it != end()) {
+ std::stringstream ss;
+ ss.str(std::string(begin(), it));
+
+ std::string line;
+ getline(ss, line);
+ std::istringstream line_s(line);
+ std::string _http_version;
+ std::string http_version;
+
+ line_s >> _http_version;
+ std::size_t separator;
+ if ((separator = _http_version.find('/')) != std::string::npos) {
+ if (_http_version.substr(0, separator) != "HTTP") {
+ return false;
+ }
+ http_version_ =
+ line.substr(separator + 1, _http_version.length() - separator - 1);
+ } else {
+ return false;
+ }
+
+ std::string status_code, status_string;
+
+ line_s >> status_code_;
+ line_s >> status_string;
+
+ auto _it = std::search(line.begin(), line.end(), status_string.begin(),
+ status_string.end());
+
+ status_string_ = std::string(_it, line.end() - 1);
+
+ std::size_t param_end;
+ std::size_t value_start;
+ while (getline(ss, line)) {
+ if ((param_end = line.find(':')) != std::string::npos) {
+ value_start = param_end + 1;
+ if ((value_start) < line.size()) {
+ if (line[value_start] == ' ') {
+ value_start++;
+ }
+ if (value_start < line.size()) {
+ headers_[line.substr(0, param_end)] =
+ line.substr(value_start, line.size() - value_start - 1);
+ }
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void HTTPResponse::parse() {
+ if (!parseHeaders()) {
+ throw errors::RuntimeException("Malformed HTTP response");
+ }
+
+ if (payload_.empty()) {
+ const char *crlf2 = "\r\n\r\n";
+ auto it =
+ std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+ if (it != this->end()) {
+ erase(begin(), it + strlen(crlf2));
+ payload_ = std::move(*dynamic_cast<std::vector<uint8_t> *>(this));
+ }
+ }
+}
+
+const std::string &HTTPResponse::getStatusCode() const { return status_code_; }
+
+const std::string &HTTPResponse::getStatusString() const {
+ return status_string_;
+}
+
+const std::string &HTTPResponse::getHttpVersion() const {
+ return http_version_;
+}
+
+} // namespace http
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/response.h b/libtransport/src/hicn/transport/http/response.h
new file mode 100755
index 000000000..e7dec8c40
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/response.h
@@ -0,0 +1,58 @@
+/*
+ * 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/http/message.h>
+#include <hicn/transport/utils/array.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPResponse : public HTTPMessage, public utils::SharableVector<uint8_t> {
+ public:
+ HTTPResponse(const HTTPHeaders &headers, const HTTPPayload &payload);
+
+ HTTPResponse();
+
+ const HTTPHeaders &getHeaders() override;
+
+ const HTTPPayload &getPayload() override;
+
+ const std::string &getStatusCode() const;
+
+ const std::string &getStatusString() const;
+
+ const std::string &getHttpVersion() const override;
+
+ void parse();
+
+ private:
+ bool parseHeaders();
+
+ private:
+ std::string status_code_;
+ std::string status_string_;
+};
+
+} // end namespace http
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/server_acceptor.cc b/libtransport/src/hicn/transport/http/server_acceptor.cc
new file mode 100755
index 000000000..717dfb642
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/server_acceptor.cc
@@ -0,0 +1,112 @@
+/*
+ * 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/http/server_acceptor.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace transport {
+
+namespace http {
+
+HTTPServerAcceptor::HTTPServerAcceptor(std::string &&server_locator,
+ OnHttpRequest callback)
+ : HTTPServerAcceptor(server_locator, callback) {}
+
+HTTPServerAcceptor::HTTPServerAcceptor(std::string &server_locator,
+ OnHttpRequest callback)
+ : callback_(callback) {
+ utils::Uri uri;
+
+ uri.parseProtocolAndLocator(server_locator);
+ std::string protocol = uri.getProtocol();
+ std::string locator = uri.getLocator();
+
+ std::transform(locator.begin(), locator.end(), locator.begin(), ::tolower);
+
+ std::transform(protocol.begin(), protocol.end(), protocol.begin(), ::tolower);
+
+ if (protocol != "http") {
+ throw errors::RuntimeException(
+ "Malformed server_locator. The locator format should be in the form "
+ "http://locator");
+ }
+
+ uint32_t locator_hash =
+ utils::hash::fnv32_buf(locator.c_str(), locator.size());
+
+ std::stringstream stream;
+ stream << std::hex << http::default_values::ipv6_first_word << ":0000";
+
+ for (uint16_t *word = (uint16_t *)&locator_hash;
+ std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash));
+ word++) {
+ stream << ":" << std::hex << *word;
+ }
+
+ stream << "::0";
+
+ std::string network = stream.str();
+
+ core::Prefix acceptor_namespace(network, 64);
+
+ std::string producer_identity = "acceptor_producer";
+ acceptor_producer_ = std::make_shared<ProducerSocket>(
+ io_service_); /*,
+ utils::Identity::generateIdentity(producer_identity));*/
+ acceptor_producer_->registerPrefix(acceptor_namespace);
+}
+
+void HTTPServerAcceptor::listen(bool async) {
+ acceptor_producer_->setSocketOption(
+ ProducerCallbacksOptions::INTEREST_INPUT,
+ (ProducerInterestCallback)bind(
+ &HTTPServerAcceptor::processIncomingInterest, this,
+ std::placeholders::_1, std::placeholders::_2));
+ acceptor_producer_->connect();
+
+ if (!async) {
+ acceptor_producer_->serveForever();
+ }
+}
+
+void HTTPServerAcceptor::processIncomingInterest(ProducerSocket &p,
+ const Interest &interest) {
+ // Temporary solution. With
+ utils::Array<uint8_t> payload = interest.getPayload();
+
+ int request_id = utils::hash::fnv32_buf(payload.data(), payload.length());
+
+ if (publishers_.find(request_id) != publishers_.end()) {
+ if (publishers_[request_id]) {
+ publishers_[request_id]->getProducer().onInterest(interest);
+ return;
+ }
+ }
+
+ publishers_[request_id] =
+ std::make_shared<HTTPServerPublisher>(interest.getName());
+ callback_(publishers_[request_id], (uint8_t *)payload.data(),
+ payload.length(), request_id);
+}
+
+std::map<int, std::shared_ptr<HTTPServerPublisher>>
+ &HTTPServerAcceptor::getPublishers() {
+ return publishers_;
+}
+
+} // namespace http
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_acceptor.h b/libtransport/src/hicn/transport/http/server_acceptor.h
new file mode 100755
index 000000000..549962414
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/server_acceptor.h
@@ -0,0 +1,62 @@
+/*
+ * 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/http/callbacks.h>
+#include <hicn/transport/http/default_values.h>
+#include <hicn/transport/http/request.h>
+#include <hicn/transport/http/server_publisher.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+#include <functional>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPServerAcceptor {
+ friend class HTTPServerPublisher;
+
+ public:
+ HTTPServerAcceptor(std::string &&server_locator, OnHttpRequest callback);
+ HTTPServerAcceptor(std::string &server_locator, OnHttpRequest callback);
+
+ void listen(bool async);
+
+ std::map<int, std::shared_ptr<HTTPServerPublisher>> &getPublishers();
+
+ // void asyncSendResponse();
+
+ // HTTPClientConnection& get(std::string &url, HTTPHeaders headers = {},
+ // HTTPPayload payload = {});
+ //
+ // HTTPResponse&& response();
+
+ private:
+ void processIncomingInterest(ProducerSocket &p, const Interest &interest);
+
+ OnHttpRequest callback_;
+ asio::io_service io_service_;
+ std::shared_ptr<ProducerSocket> acceptor_producer_;
+
+ std::map<int, std::shared_ptr<HTTPServerPublisher>> publishers_;
+};
+
+} // end namespace http
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_publisher.cc b/libtransport/src/hicn/transport/http/server_publisher.cc
new file mode 100755
index 000000000..012f36091
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/server_publisher.cc
@@ -0,0 +1,173 @@
+/*
+ * 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/http/server_publisher.h>
+#include <hicn/transport/utils/literals.h>
+
+namespace transport {
+
+namespace http {
+
+HTTPServerPublisher::HTTPServerPublisher(const core::Name &content_name)
+ : content_name_(content_name, true) {
+ std::string identity = "acceptor_producer";
+ producer_ = std::make_unique<ProducerSocket>(io_service_);
+ // utils::Identity::generateIdentity(identity));
+ core::Prefix publisher_prefix(content_name_, 128);
+ producer_->registerPrefix(publisher_prefix);
+}
+
+HTTPServerPublisher::~HTTPServerPublisher() {
+ if (timer_) {
+ this->timer_->cancel();
+ }
+}
+
+HTTPServerPublisher &HTTPServerPublisher::attachPublisher() {
+ // Create a new publisher
+ producer_->setSocketOption(GeneralTransportOptions::DATA_PACKET_SIZE,
+ 1410_U32);
+ producer_->connect();
+ return *this;
+}
+
+HTTPServerPublisher &HTTPServerPublisher::setTimeout(
+ const std::chrono::milliseconds &timeout, bool timeout_renewal) {
+ std::shared_ptr<typename ProducerSocket::Portal> portal;
+ producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal);
+ timer_ =
+ std::make_unique<asio::steady_timer>(portal->getIoService(), timeout);
+
+ wait_callback_ = [this](const std::error_code &e) {
+ if (!e) {
+ producer_->stop();
+ }
+ };
+
+ if (timeout_renewal) {
+ interest_enter_callback_ = [this, timeout](ProducerSocket &p,
+ const Interest &interest) {
+ this->timer_->cancel();
+ this->timer_->expires_from_now(timeout);
+ this->timer_->async_wait(wait_callback_);
+ };
+
+ producer_->setSocketOption(
+ ProducerCallbacksOptions::CACHE_HIT,
+ (ProducerInterestCallback)interest_enter_callback_);
+ }
+
+ timer_->async_wait(wait_callback_);
+
+ return *this;
+}
+
+void HTTPServerPublisher::publishContent(
+ const uint8_t *buf, size_t buffer_size,
+ std::chrono::milliseconds content_lifetime, bool is_last) {
+ if (producer_) {
+ producer_->setSocketOption(
+ GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+ static_cast<uint32_t>(content_lifetime.count()));
+ producer_->produce(content_name_, buf, buffer_size, is_last);
+ // producer_->setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+ // [this](ProducerSocket &p, const
+ // core::Interest &interest){
+ // producer_->stop();
+ // });
+ }
+}
+
+template <typename Handler>
+void HTTPServerPublisher::asyncPublishContent(
+ const uint8_t *buf, size_t buffer_size,
+ std::chrono::milliseconds content_lifetime, Handler &&handler,
+ bool is_last) {
+ if (producer_) {
+ producer_->setSocketOption(
+ GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+ static_cast<uint32_t>(content_lifetime.count()));
+ producer_->asyncProduce(content_name_, buf, buffer_size,
+ std::forward<Handler>(handler), is_last);
+ }
+}
+
+void HTTPServerPublisher::serveClients() { producer_->serveForever(); }
+
+void HTTPServerPublisher::stop() {
+ std::shared_ptr<typename ProducerSocket::Portal> portal_ptr;
+ producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal_ptr);
+ portal_ptr->getIoService().stop();
+}
+
+ProducerSocket &HTTPServerPublisher::getProducer() { return *producer_; }
+
+void HTTPServerPublisher::setPublisherName(std::string &name,
+ std::string &mask) {
+ // Name represents the last 64 bits of the ipv6 address.
+ // It is an ipv6 address with the first 64 bits set to 0
+ uint16_t i;
+ std::string s = content_name_.toString();
+ std::shared_ptr<core::Sockaddr> sockaddr = content_name_.getAddress();
+ in6_addr name_ipv6 = ((core::Sockaddr6 *)sockaddr.get())->sin6_addr;
+
+ in6_addr bitmask, new_address, _name;
+
+ if (inet_pton(AF_INET6, mask.c_str(), &bitmask) != 1) {
+ throw errors::RuntimeException("Error during conversion to ipv6 address.");
+ }
+
+ if (inet_pton(AF_INET6, name.c_str(), &_name) != 1) {
+ throw errors::RuntimeException("Error during conversion to ipv6 address.");
+ }
+
+ for (i = 0; i < sizeof(new_address.s6_addr); i++) {
+ new_address.s6_addr[i] = name_ipv6.s6_addr[i] & bitmask.s6_addr[i];
+ }
+
+ for (i = 0; i < sizeof(new_address.s6_addr); i++) {
+ new_address.s6_addr[i] |= _name.s6_addr[i] & ~bitmask.s6_addr[i];
+ }
+
+ // Effectively change the name
+ char str[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &new_address, str, INET6_ADDRSTRLEN);
+ std::string str2(str);
+
+ core::Name new_name(str2, 0);
+
+ // If the new name differs from the one required by the consumer part, send a
+ // manifest
+ if (!new_name.equals(content_name_, false)) {
+ // Publish manifest pointing to the new name
+
+ auto manifest =
+ std::make_shared<ContentObjectManifest>(content_name_.setSuffix(0));
+
+ content_name_ = core::Name(str2, 0);
+
+ // manifest->setNameList(content_name_);
+ manifest->setLifetime(4000 * 1000);
+ manifest->encode();
+ producer_->produce(*manifest);
+
+ core::Prefix ns(content_name_, 128);
+ producer_->registerPrefix(ns);
+ }
+}
+
+} // namespace http
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_publisher.h b/libtransport/src/hicn/transport/http/server_publisher.h
new file mode 100755
index 000000000..91f7e43e9
--- /dev/null
+++ b/libtransport/src/hicn/transport/http/server_publisher.h
@@ -0,0 +1,72 @@
+/*
+ * 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/http/default_values.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+#include <functional>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+using namespace interface;
+using namespace core;
+
+class HTTPServerPublisher {
+ public:
+ HTTPServerPublisher(const core::Name &content_name);
+
+ ~HTTPServerPublisher();
+
+ void publishContent(const uint8_t *buf, size_t buffer_size,
+ std::chrono::milliseconds content_lifetime, bool is_last);
+
+ template <typename Handler>
+ void asyncPublishContent(const uint8_t *buf, size_t buffer_size,
+ std::chrono::milliseconds content_lifetime,
+ Handler &&handler, bool is_last);
+
+ void serveClients();
+
+ void stop();
+
+ ProducerSocket &getProducer();
+
+ HTTPServerPublisher &setTimeout(const std::chrono::milliseconds &timeout,
+ bool timeout_renewal);
+
+ HTTPServerPublisher &attachPublisher();
+
+ void setPublisherName(std::string &name, std::string &mask);
+
+ private:
+ Name content_name_;
+ std::unique_ptr<asio::steady_timer> timer_;
+ asio::io_service io_service_;
+ std::unique_ptr<ProducerSocket> producer_;
+ ProducerInterestCallback interest_enter_callback_;
+ utils::UserCallback wait_callback_;
+
+ utils::SharableVector<uint8_t> receive_buffer_;
+};
+
+} // end namespace http
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
new file mode 100755
index 000000000..cbf371bac
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
@@ -0,0 +1,38 @@
+# 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}/socket.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_consumer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/async_transport.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/full_duplex_socket.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/publication_options.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_default_values.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_keys.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/full_duplex_socket.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_consumer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc
+)
+
+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/interfaces/async_transport.h b/libtransport/src/hicn/transport/interfaces/async_transport.h
new file mode 100755
index 000000000..492b4ec26
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/async_transport.h
@@ -0,0 +1,640 @@
+
+/*
+ * 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/interfaces/publication_options.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <sys/uio.h>
+#include <memory>
+
+namespace transport {
+
+namespace interface {
+
+/*
+ * flags given by the application for write* calls
+ */
+enum class WriteFlags : uint32_t {
+ NONE = 0x00,
+ /*
+ * Whether to delay the output until a subsequent non-corked write.
+ * (Note: may not be supported in all subclasses or on all platforms.)
+ */
+ CORK = 0x01,
+ /*
+ * for a socket that has ACK latency enabled, it will cause the kernel
+ * to fire a TCP ESTATS event when the last byte of the given write call
+ * will be acknowledged.
+ */
+ EOR = 0x02,
+ /*
+ * this indicates that only the write side of socket should be shutdown
+ */
+ WRITE_SHUTDOWN = 0x04,
+ /*
+ * use msg zerocopy if allowed
+ */
+ WRITE_MSG_ZEROCOPY = 0x08,
+};
+
+/*
+ * union operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator|(WriteFlags a, WriteFlags b) {
+ return static_cast<WriteFlags>(static_cast<uint32_t>(a) |
+ static_cast<uint32_t>(b));
+}
+
+/*
+ * compound assignment union operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags &operator|=(WriteFlags &a, WriteFlags b) {
+ a = a | b;
+ return a;
+}
+
+/*
+ * intersection operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator&(WriteFlags a, WriteFlags b) {
+ return static_cast<WriteFlags>(static_cast<uint32_t>(a) &
+ static_cast<uint32_t>(b));
+}
+
+/*
+ * compound assignment intersection operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags &operator&=(WriteFlags &a, WriteFlags b) {
+ a = a & b;
+ return a;
+}
+
+/*
+ * exclusion parameter
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator~(WriteFlags a) {
+ return static_cast<WriteFlags>(~static_cast<uint32_t>(a));
+}
+
+/*
+ * unset operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags unSet(WriteFlags a, WriteFlags b) {
+ return a & ~b;
+}
+
+/*
+ * inclusion operator
+ */
+TRANSPORT_ALWAYS_INLINE bool isSet(WriteFlags a, WriteFlags b) {
+ return (a & b) == b;
+}
+
+class ConnectCallback {
+ public:
+ virtual ~ConnectCallback() = default;
+
+ /**
+ * connectSuccess() will be invoked when the connection has been
+ * successfully established.
+ */
+ virtual void connectSuccess() noexcept = 0;
+
+ /**
+ * connectErr() will be invoked if the connection attempt fails.
+ *
+ * @param ex An exception describing the error that occurred.
+ */
+ virtual void connectErr(const std::error_code ec) noexcept = 0;
+};
+
+/**
+ * AsyncSocket defines an asynchronous API for streaming I/O.
+ *
+ * This class provides an API to for asynchronously waiting for data
+ * on a streaming transport, and for asynchronously sending data.
+ *
+ * The APIs for reading and writing are intentionally asymmetric. Waiting for
+ * data to read is a persistent API: a callback is installed, and is notified
+ * whenever new data is available. It continues to be notified of new events
+ * until it is uninstalled.
+ *
+ * AsyncSocket does not provide read timeout functionality, because it
+ * typically cannot determine when the timeout should be active. Generally, a
+ * timeout should only be enabled when processing is blocked waiting on data
+ * from the remote endpoint. For server-side applications, the timeout should
+ * not be active if the server is currently processing one or more outstanding
+ * requests on this transport. For client-side applications, the timeout
+ * should not be active if there are no requests pending on the transport.
+ * Additionally, if a client has multiple pending requests, it will ususally
+ * want a separate timeout for each request, rather than a single read timeout.
+ *
+ * The write API is fairly intuitive: a user can request to send a block of
+ * data, and a callback will be informed once the entire block has been
+ * transferred to the kernel, or on error. AsyncSocket does provide a send
+ * timeout, since most callers want to give up if the remote end stops
+ * responding and no further progress can be made sending the data.
+ */
+class AsyncSocket {
+ public:
+ /**
+ * Close the transport.
+ *
+ * This gracefully closes the transport, waiting for all pending write
+ * requests to complete before actually closing the underlying transport.
+ *
+ * If a read callback is set, readEOF() will be called immediately. If there
+ * are outstanding write requests, the close will be delayed until all
+ * remaining writes have completed. No new writes may be started after
+ * close() has been called.
+ */
+ virtual void close() = 0;
+
+ /**
+ * Close the transport immediately.
+ *
+ * This closes the transport immediately, dropping any outstanding data
+ * waiting to be written.
+ *
+ * If a read callback is set, readEOF() will be called immediately.
+ * If there are outstanding write requests, these requests will be aborted
+ * and writeError() will be invoked immediately on all outstanding write
+ * callbacks.
+ */
+ virtual void closeNow() = 0;
+
+ /**
+ * Perform a half-shutdown of the write side of the transport.
+ *
+ * The caller should not make any more calls to write() or writev() after
+ * shutdownWrite() is called. Any future write attempts will fail
+ * immediately.
+ *
+ * Not all transport types support half-shutdown. If the underlying
+ * transport does not support half-shutdown, it will fully shutdown both the
+ * read and write sides of the transport. (Fully shutting down the socket is
+ * better than doing nothing at all, since the caller may rely on the
+ * shutdownWrite() call to notify the other end of the connection that no
+ * more data can be read.)
+ *
+ * If there is pending data still waiting to be written on the transport,
+ * the actual shutdown will be delayed until the pending data has been
+ * written.
+ *
+ * Note: There is no corresponding shutdownRead() equivalent. Simply
+ * uninstall the read callback if you wish to stop reading. (On TCP sockets
+ * at least, shutting down the read side of the socket is a no-op anyway.)
+ */
+ virtual void shutdownWrite() = 0;
+
+ /**
+ * Perform a half-shutdown of the write side of the transport.
+ *
+ * shutdownWriteNow() is identical to shutdownWrite(), except that it
+ * immediately performs the shutdown, rather than waiting for pending writes
+ * to complete. Any pending write requests will be immediately failed when
+ * shutdownWriteNow() is called.
+ */
+ virtual void shutdownWriteNow() = 0;
+
+ /**
+ * Determine if transport is open and ready to read or write.
+ *
+ * Note that this function returns false on EOF; you must also call error()
+ * to distinguish between an EOF and an error.
+ *
+ * @return true iff the transport is open and ready, false otherwise.
+ */
+ virtual bool good() const = 0;
+
+ /**
+ * Determine if the transport is readable or not.
+ *
+ * @return true iff the transport is readable, false otherwise.
+ */
+ virtual bool readable() const = 0;
+
+ /**
+ * Determine if the transport is writable or not.
+ *
+ * @return true iff the transport is writable, false otherwise.
+ */
+ virtual bool writable() const {
+ // By default return good() - leave it to implementers to override.
+ return good();
+ }
+
+ /**
+ * Determine if the there is pending data on the transport.
+ *
+ * @return true iff the if the there is pending data, false otherwise.
+ */
+ virtual bool isPending() const { return readable(); }
+
+ /**
+ * Determine if transport is connected to the endpoint
+ *
+ * @return false iff the transport is connected, otherwise true
+ */
+ virtual bool connected() const = 0;
+
+ /**
+ * Determine if an error has occurred with this transport.
+ *
+ * @return true iff an error has occurred (not EOF).
+ */
+ virtual bool error() const = 0;
+
+ // /**
+ // * Attach the transport to a EventBase.
+ // *
+ // * This may only be called if the transport is not currently attached to a
+ // * EventBase (by an earlier call to detachEventBase()).
+ // *
+ // * This method must be invoked in the EventBase's thread.
+ // */
+ // virtual void attachEventBase(EventBase* eventBase) = 0;
+
+ // /**
+ // * Detach the transport from its EventBase.
+ // *
+ // * This may only be called when the transport is idle and has no reads or
+ // * writes pending. Once detached, the transport may not be used again
+ // until
+ // * it is re-attached to a EventBase by calling attachEventBase().
+ // *
+ // * This method must be called from the current EventBase's thread.
+ // */
+ // virtual void detachEventBase() = 0;
+
+ // /**
+ // * Determine if the transport can be detached.
+ // *
+ // * This method must be called from the current EventBase's thread.
+ // */
+ // virtual bool isDetachable() const = 0;
+
+ /**
+ * Set the send timeout.
+ *
+ * If write requests do not make any progress for more than the specified
+ * number of milliseconds, fail all pending writes and close the transport.
+ *
+ * If write requests are currently pending when setSendTimeout() is called,
+ * the timeout interval is immediately restarted using the new value.
+ *
+ * @param milliseconds The timeout duration, in milliseconds. If 0, no
+ * timeout will be used.
+ */
+ virtual void setSendTimeout(uint32_t milliseconds) = 0;
+
+ /**
+ * Get the send timeout.
+ *
+ * @return Returns the current send timeout, in milliseconds. A return value
+ * of 0 indicates that no timeout is set.
+ */
+ virtual uint32_t getSendTimeout() const = 0;
+
+ virtual void connect(ConnectCallback *callback,
+ const core::Prefix &prefix_) = 0;
+
+ // /**
+ // * Get the address of the local endpoint of this transport.
+ // *
+ // * This function may throw AsyncSocketException on error.
+ // *
+ // * @param address The local address will be stored in the specified
+ // * SocketAddress.
+ // */
+ // virtual void getLocalAddress(* address) const = 0;
+
+ virtual size_t getAppBytesWritten() const = 0;
+ virtual size_t getRawBytesWritten() const = 0;
+ virtual size_t getAppBytesReceived() const = 0;
+ virtual size_t getRawBytesReceived() const = 0;
+
+ class BufferCallback {
+ public:
+ virtual ~BufferCallback() {}
+ virtual void onEgressBuffered() = 0;
+ virtual void onEgressBufferCleared() = 0;
+ };
+
+ ~AsyncSocket() = default;
+};
+
+class AsyncAcceptor {
+ public:
+ class AcceptCallback {
+ public:
+ virtual ~AcceptCallback() = default;
+
+ /**
+ * connectionAccepted() is called whenever a new client connection is
+ * received.
+ *
+ * The AcceptCallback will remain installed after connectionAccepted()
+ * returns.
+ *
+ * @param fd The newly accepted client socket. The AcceptCallback
+ * assumes ownership of this socket, and is responsible
+ * for closing it when done. The newly accepted file
+ * descriptor will have already been put into
+ * non-blocking mode.
+ * @param clientAddr A reference to a SocketAddress struct containing the
+ * client's address. This struct is only guaranteed to
+ * remain valid until connectionAccepted() returns.
+ */
+ virtual void connectionAccepted(
+ const core::Name &subscriber_name) noexcept = 0;
+
+ /**
+ * acceptError() is called if an error occurs while accepting.
+ *
+ * The AcceptCallback will remain installed even after an accept error,
+ * as the errors are typically somewhat transient, such as being out of
+ * file descriptors. The server socket must be explicitly stopped if you
+ * wish to stop accepting after an error.
+ *
+ * @param ex An exception representing the error.
+ */
+ virtual void acceptError(const std::exception &ex) noexcept = 0;
+
+ /**
+ * acceptStarted() will be called in the callback's EventBase thread
+ * after this callback has been added to the AsyncServerSocket.
+ *
+ * acceptStarted() will be called before any calls to connectionAccepted()
+ * or acceptError() are made on this callback.
+ *
+ * acceptStarted() makes it easier for callbacks to perform initialization
+ * inside the callback thread. (The call to addAcceptCallback() must
+ * always be made from the AsyncServerSocket's primary EventBase thread.
+ * acceptStarted() provides a hook that will always be invoked in the
+ * callback's thread.)
+ *
+ * Note that the call to acceptStarted() is made once the callback is
+ * added, regardless of whether or not the AsyncServerSocket is actually
+ * accepting at the moment. acceptStarted() will be called even if the
+ * AsyncServerSocket is paused when the callback is added (including if
+ * the initial call to startAccepting() on the AsyncServerSocket has not
+ * been made yet).
+ */
+ virtual void acceptStarted() noexcept {}
+
+ /**
+ * acceptStopped() will be called when this AcceptCallback is removed from
+ * the AsyncServerSocket, or when the AsyncServerSocket is destroyed,
+ * whichever occurs first.
+ *
+ * No more calls to connectionAccepted() or acceptError() will be made
+ * after acceptStopped() is invoked.
+ */
+ virtual void acceptStopped() noexcept {}
+ };
+
+ /**
+ * Wait for subscribers
+ *
+ */
+ virtual void waitForSubscribers(AcceptCallback *cb) = 0;
+};
+
+class AsyncReader {
+ public:
+ class ReadCallback {
+ public:
+ virtual ~ReadCallback() = default;
+
+ /**
+ * When data becomes available, getReadBuffer() will be invoked to get the
+ * buffer into which data should be read.
+ *
+ * This method allows the ReadCallback to delay buffer allocation until
+ * data becomes available. This allows applications to manage large
+ * numbers of idle connections, without having to maintain a separate read
+ * buffer for each idle connection.
+ *
+ * It is possible that in some cases, getReadBuffer() may be called
+ * multiple times before readDataAvailable() is invoked. In this case, the
+ * data will be written to the buffer returned from the most recent call to
+ * readDataAvailable(). If the previous calls to readDataAvailable()
+ * returned different buffers, the ReadCallback is responsible for ensuring
+ * that they are not leaked.
+ *
+ * If getReadBuffer() throws an exception, returns a nullptr buffer, or
+ * returns a 0 length, the ReadCallback will be uninstalled and its
+ * readError() method will be invoked.
+ *
+ * getReadBuffer() is not allowed to change the transport state before it
+ * returns. (For example, it should never uninstall the read callback, or
+ * set a different read callback.)
+ *
+ * @param bufReturn getReadBuffer() should update *bufReturn to contain the
+ * address of the read buffer. This parameter will never
+ * be nullptr.
+ * @param lenReturn getReadBuffer() should update *lenReturn to contain the
+ * maximum number of bytes that may be written to the read
+ * buffer. This parameter will never be nullptr.
+ *
+ *
+ * XXX TODO this does not seems to be completely true Checlk i/.
+ */
+ virtual void getReadBuffer(void **bufReturn, size_t *lenReturn) = 0;
+
+ /**
+ * readDataAvailable() will be invoked when data has been successfully read
+ * into the buffer returned by the last call to getReadBuffer().
+ *
+ * The read callback remains installed after readDataAvailable() returns.
+ * It must be explicitly uninstalled to stop receiving read events.
+ * getReadBuffer() will be called at least once before each call to
+ * readDataAvailable(). getReadBuffer() will also be called before any
+ * call to readEOF().
+ *
+ * @param len The number of bytes placed in the buffer.
+ */
+
+ virtual void readDataAvailable(size_t len) noexcept = 0;
+
+ /**
+ * When data becomes available, isBufferMovable() will be invoked to figure
+ * out which API will be used, readBufferAvailable() or
+ * readDataAvailable(). If isBufferMovable() returns true, that means
+ * ReadCallback supports the IOBuf ownership transfer and
+ * readBufferAvailable() will be used. Otherwise, not.
+
+ * By default, isBufferMovable() always return false. If
+ * readBufferAvailable() is implemented and to be invoked, You should
+ * overwrite isBufferMovable() and return true in the inherited class.
+ *
+ * This method allows the AsyncSocket/AsyncSSLSocket do buffer allocation by
+ * itself until data becomes available. Compared with the pre/post buffer
+ * allocation in getReadBuffer()/readDataAvailabe(), readBufferAvailable()
+ * has two advantages. First, this can avoid memcpy. E.g., in
+ * AsyncSSLSocket, the decrypted data was copied from the openssl internal
+ * buffer to the readbuf buffer. With the buffer ownership transfer, the
+ * internal buffer can be directly "moved" to ReadCallback. Second, the
+ * memory allocation can be more precise. The reason is
+ * AsyncSocket/AsyncSSLSocket can allocate the memory of precise size
+ * because they have more context about the available data than
+ * ReadCallback. Think about the getReadBuffer() pre-allocate 4072 bytes
+ * buffer, but the available data is always 16KB (max OpenSSL record size).
+ */
+
+ virtual bool isBufferMovable() noexcept { return false; }
+
+ /**
+ * Suggested buffer size, allocated for read operations,
+ * if callback is movable and supports folly::IOBuf
+ */
+
+ virtual size_t maxBufferSize() const {
+ return 64 * 1024; // 64K
+ }
+
+ /**
+ * readBufferAvailable() will be invoked when data has been successfully
+ * read.
+ *
+ * Note that only either readBufferAvailable() or readDataAvailable() will
+ * be invoked according to the return value of isBufferMovable(). The timing
+ * and aftereffect of readBufferAvailable() are the same as
+ * readDataAvailable()
+ *
+ * @param readBuf The unique pointer of read buffer.
+ */
+
+ // virtual void readBufferAvailable(uint8_t** buffer, std::size_t
+ // *buf_length) noexcept {}
+
+ virtual void readBufferAvailable(
+ utils::SharableVector<uint8_t> &&buffer) noexcept {}
+
+ // virtual void readBufferAvailable(utils::SharableBuffer<uint8_t>&& buffer)
+ // noexcept {}
+
+ /**
+ * readEOF() will be invoked when the transport is closed.
+ *
+ * The read callback will be automatically uninstalled immediately before
+ * readEOF() is invoked.
+ */
+ virtual void readEOF() noexcept = 0;
+
+ /**
+ * readError() will be invoked if an error occurs reading from the
+ * transport.
+ *
+ * The read callback will be automatically uninstalled immediately before
+ * readError() is invoked.
+ *
+ * @param ex An exception describing the error that occurred.
+ */
+ virtual void readErr(const std::error_code ec) noexcept = 0;
+ };
+
+ // Read methods that aren't part of AsyncTransport.
+ virtual void setReadCB(ReadCallback *callback) = 0;
+ virtual ReadCallback *getReadCallback() const = 0;
+
+ protected:
+ virtual ~AsyncReader() = default;
+};
+
+class AsyncWriter {
+ public:
+ class WriteCallback {
+ public:
+ virtual ~WriteCallback() = default;
+
+ /**
+ * writeSuccess() will be invoked when all of the data has been
+ * successfully written.
+ *
+ * Note that this mainly signals that the buffer containing the data to
+ * write is no longer needed and may be freed or re-used. It does not
+ * guarantee that the data has been fully transmitted to the remote
+ * endpoint. For example, on socket-based transports, writeSuccess() only
+ * indicates that the data has been given to the kernel for eventual
+ * transmission.
+ */
+ virtual void writeSuccess() noexcept = 0;
+
+ /**
+ * writeError() will be invoked if an error occurs writing the data.
+ *
+ * @param bytesWritten The number of bytes that were successfull
+ * @param ex An exception describing the error that occurred.
+ */
+ virtual void writeErr(size_t bytesWritten) noexcept = 0;
+ };
+
+ /**
+ * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+ * or writeErr() will be invoked when the write completes. If you supply
+ * the same WriteCallback object for multiple write() calls, it will be
+ * invoked exactly once per call. The only way to cancel outstanding
+ * write requests is to close the socket (e.g., with closeNow() or
+ * shutdownWriteNow()). When closing the socket this way, writeErr() will
+ * still be invoked once for each outstanding write operation.
+ */
+ virtual void write(WriteCallback *callback, const void *buf, size_t bytes,
+ const PublicationOptions &options,
+ WriteFlags flags = WriteFlags::NONE) = 0;
+
+ /**
+ * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+ * or writeErr() will be invoked when the write completes. If you supply
+ * the same WriteCallback object for multiple write() calls, it will be
+ * invoked exactly once per call. The only way to cancel outstanding
+ * write requests is to close the socket (e.g., with closeNow() or
+ * shutdownWriteNow()). When closing the socket this way, writeErr() will
+ * still be invoked once for each outstanding write operation.
+ */
+ virtual void write(WriteCallback *callback,
+ utils::SharableVector<uint8_t> &&output_buffer,
+ const PublicationOptions &options,
+ WriteFlags flags = WriteFlags::NONE) = 0;
+
+ // /**
+ // * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+ // * or writeErr() will be invoked when the write completes. If you supply
+ // * the same WriteCallback object for multiple write() calls, it will be
+ // * invoked exactly once per call. The only way to cancel outstanding
+ // * write requests is to close the socket (e.g., with closeNow() or
+ // * shutdownWriteNow()). When closing the socket this way, writeErr() will
+ // * still be invoked once for each outstanding write operation.
+ // */
+ // virtual void writeChain(
+ // WriteCallback* callback,
+ // std::unique_ptr<IOBuf>&& buf,
+ // WriteFlags flags = WriteFlags::NONE) = 0;
+
+ virtual void setWriteCB(WriteCallback *callback) = 0;
+ virtual WriteCallback *getWriteCallback() const = 0;
+
+ protected:
+ virtual ~AsyncWriter() = default;
+};
+
+} // namespace interface
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc
new file mode 100755
index 000000000..7b6342262
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc
@@ -0,0 +1,490 @@
+/*
+ * 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/interfaces/full_duplex_socket.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <memory>
+
+namespace transport {
+
+namespace interface {
+
+static const std::string producer_identity = "producer_socket";
+
+AsyncFullDuplexSocket::AsyncFullDuplexSocket(const Prefix &locator)
+ : AsyncFullDuplexSocket(locator, internal_io_service_) {}
+
+AsyncFullDuplexSocket::AsyncFullDuplexSocket(const Prefix &locator,
+ asio::io_service &io_service)
+ : locator_(locator),
+ incremental_suffix_(0),
+ io_service_(io_service),
+ work_(io_service),
+ producer_(std::make_unique<ProducerSocket>(io_service_)),
+ consumer_(std::make_unique<ConsumerSocket>(
+ TransportProtocolAlgorithms::RAAQM /* , io_service_ */)),
+ read_callback_(nullptr),
+ write_callback_(nullptr),
+ connect_callback_(nullptr),
+ accept_callback_(nullptr),
+ internal_connect_callback_(new OnConnectCallback(*this)),
+ internal_signal_callback_(new OnSignalCallback(*this)),
+ send_timeout_milliseconds_(~0),
+ counters_({0}),
+ receive_buffer_(std::make_shared<utils::SharableVector<uint8_t>>()) {
+ using namespace transport;
+ using namespace std::placeholders;
+ producer_->registerPrefix(locator);
+
+ producer_->setSocketOption(
+ ProducerCallbacksOptions::CACHE_MISS,
+ std::bind(&AsyncFullDuplexSocket::onControlInterest, this, _1, _2));
+
+ producer_->setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE,
+ uint32_t{150000});
+
+ producer_->setSocketOption(
+ ProducerCallbacksOptions::CONTENT_PRODUCED,
+ std::bind(&AsyncFullDuplexSocket::onContentProduced, this, _1, _2, _3));
+
+ producer_->connect();
+
+ consumer_->setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
+ (ConsumerContentObjectVerificationCallback)[](
+ ConsumerSocket & s, const ContentObject &c)
+ ->bool { return true; });
+
+ consumer_->setSocketOption(
+ ConsumerCallbacksOptions::CONTENT_RETRIEVED,
+ std::bind(&AsyncFullDuplexSocket::onContentRetrieved, this, _1, _2, _3));
+
+ consumer_->setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX,
+ uint32_t{4});
+
+ consumer_->connect();
+}
+
+void AsyncFullDuplexSocket::close() {
+ this->consumer_->stop();
+ this->producer_->stop();
+}
+
+void AsyncFullDuplexSocket::closeNow() { close(); }
+
+void AsyncFullDuplexSocket::shutdownWrite() { producer_->stop(); }
+
+void AsyncFullDuplexSocket::shutdownWriteNow() { shutdownWrite(); }
+
+bool AsyncFullDuplexSocket::good() const { return true; }
+
+bool AsyncFullDuplexSocket::readable() const {
+ // TODO return status of consumer socket
+ return true;
+}
+
+bool AsyncFullDuplexSocket::writable() const {
+ // TODO return status of producer socket
+ return true;
+}
+
+bool AsyncFullDuplexSocket::isPending() const {
+ // TODO save if there are production operation in the ops queue
+ // in producer socket
+ return true;
+}
+
+bool AsyncFullDuplexSocket::connected() const {
+ // No real connection here (ICN world). Return good
+ return good();
+}
+
+bool AsyncFullDuplexSocket::error() const { return !good(); }
+
+void AsyncFullDuplexSocket::setSendTimeout(uint32_t milliseconds) {
+ // TODO if production takes too much to complete
+ // let's abort the operation.
+
+ // Normally with hicn this should be done for content
+ // pull, not for production.
+
+ send_timeout_milliseconds_ = milliseconds;
+}
+
+uint32_t AsyncFullDuplexSocket::getSendTimeout() const {
+ return send_timeout_milliseconds_;
+}
+
+size_t AsyncFullDuplexSocket::getAppBytesWritten() const {
+ return counters_.app_bytes_written_;
+}
+
+size_t AsyncFullDuplexSocket::getRawBytesWritten() const { return 0; }
+
+size_t AsyncFullDuplexSocket::getAppBytesReceived() const {
+ return counters_.app_bytes_read_;
+}
+
+size_t AsyncFullDuplexSocket::getRawBytesReceived() const { return 0; }
+
+void AsyncFullDuplexSocket::connect(ConnectCallback *callback,
+ const core::Prefix &prefix) {
+ connect_callback_ = callback;
+
+ // Create an interest for a subscription
+ auto interest =
+ core::Interest::Ptr(new core::Interest(prefix.makeRandomName()));
+ auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+ _payload->append(sizeof(ActionMessage));
+ auto payload = _payload->writableData();
+ ActionMessage *subscription_message =
+ reinterpret_cast<ActionMessage *>(payload);
+ subscription_message->header.msg_type = MessageType::ACTION;
+ subscription_message->action = Action::SUBSCRIBE;
+ subscription_message->header.reserved[0] = 0;
+ subscription_message->header.reserved[1] = 0;
+
+ // Set the name the other part should use for notifying a content production
+ sync_notification_ = std::move(locator_.makeRandomName());
+ sync_notification_.copyToDestination(
+ reinterpret_cast<uint8_t *>(subscription_message->name));
+
+ TRANSPORT_LOGI(
+ "Trying to connect. Sending interest: %s, name for notifications: %s",
+ prefix.getName().toString().c_str(),
+ sync_notification_.toString().c_str());
+
+ interest->setLifetime(1000);
+ interest->appendPayload(std::move(_payload));
+ consumer_->asyncSendInterest(std::move(interest),
+ internal_connect_callback_.get());
+}
+
+void AsyncFullDuplexSocket::write(WriteCallback *callback, const void *buf,
+ size_t bytes,
+ const PublicationOptions &options,
+ WriteFlags flags) {
+ using namespace transport;
+
+ // 1 asynchronously write the content. I assume here the
+ // buffer contains the whole application frame. FIXME: check
+ // if this is true and fix it accordingly
+ std::cout << "Size of the PAYLOAD: " << bytes << std::endl;
+
+ if (bytes > core::Packet::default_mtu - sizeof(PayloadMessage)) {
+ TRANSPORT_LOGI("Producing content with name %s",
+ options.name.toString().c_str());
+ producer_->asyncProduce(options.name,
+ reinterpret_cast<const uint8_t *>(buf), bytes);
+ signalProductionToSubscribers(options.name);
+ } else {
+ TRANSPORT_LOGI("Sending payload through interest");
+ piggybackPayloadToSubscribers(
+ options.name, reinterpret_cast<const uint8_t *>(buf), bytes);
+ }
+}
+
+void AsyncFullDuplexSocket::write(
+ WriteCallback *callback, utils::SharableVector<uint8_t> &&output_buffer,
+ const PublicationOptions &options, WriteFlags flags) {
+ using namespace transport;
+
+ // 1 asynchronously write the content. I assume here the
+ // buffer contains the whole application frame. FIXME: check
+ // if this is true and fix it accordingly
+ std::cout << "Size of the PAYLOAD: " << output_buffer.size() << std::endl;
+
+ if (output_buffer.size() >
+ core::Packet::default_mtu - sizeof(PayloadMessage)) {
+ TRANSPORT_LOGI("Producing content with name %s",
+ options.name.toString().c_str());
+ producer_->asyncProduce(options.name, std::move(output_buffer));
+ signalProductionToSubscribers(options.name);
+ } else {
+ TRANSPORT_LOGI("Sending payload through interest");
+ piggybackPayloadToSubscribers(options.name, &output_buffer[0],
+ output_buffer.size());
+ }
+}
+
+void AsyncFullDuplexSocket::piggybackPayloadToSubscribers(
+ const core::Name &name, const uint8_t *buffer, std::size_t bytes) {
+ for (auto &sub : subscribers_) {
+ auto interest = core::Interest::Ptr(new core::Interest(name));
+ auto _payload = utils::MemBuf::create(bytes + sizeof(PayloadMessage));
+ _payload->append(bytes + sizeof(PayloadMessage));
+ auto payload = _payload->writableData();
+
+ PayloadMessage *interest_payload =
+ reinterpret_cast<PayloadMessage *>(payload);
+ interest_payload->header.msg_type = MessageType::PAYLOAD;
+ interest_payload->header.reserved[0] = 0;
+ interest_payload->header.reserved[1] = 0;
+ interest_payload->reserved[0] = 0;
+ std::memcpy(payload + sizeof(PayloadMessage), buffer, bytes);
+ interest->appendPayload(std::move(_payload));
+
+ // Set the timeout of 0.2 second
+ interest->setLifetime(1000);
+ interest->setName(sub);
+ interest->getWritableName().setSuffix(incremental_suffix_++);
+ // TRANSPORT_LOGI("Sending signalization to %s",
+ // interest->getName().toString().c_str());
+
+ consumer_->asyncSendInterest(std::move(interest),
+ internal_signal_callback_.get());
+ }
+}
+
+void AsyncFullDuplexSocket::signalProductionToSubscribers(
+ const core::Name &name) {
+ // Signal the other part we are producing a content
+ // Create an interest for a subscription
+
+ for (auto &sub : subscribers_) {
+ auto interest = core::Interest::Ptr(new core::Interest(name));
+ // Todo consider using preallocated pool of membufs
+ auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+ _payload->append(sizeof(ActionMessage));
+ auto payload = const_cast<uint8_t *>(interest->getPayload().data());
+
+ ActionMessage *produce_notification =
+ reinterpret_cast<ActionMessage *>(payload);
+ produce_notification->header.msg_type = MessageType::ACTION;
+ produce_notification->action = Action::SIGNAL_PRODUCTION;
+ produce_notification->header.reserved[0] = 0;
+ produce_notification->header.reserved[1] = 0;
+ name.copyToDestination(
+ reinterpret_cast<uint8_t *>(produce_notification->name));
+ interest->appendPayload(std::move(_payload));
+
+ // Set the timeout of 0.2 second
+ interest->setLifetime(1000);
+ interest->setName(sub);
+ interest->getWritableName().setSuffix(incremental_suffix_++);
+ // TRANSPORT_LOGI("Sending signalization to %s",
+ // interest->getName().toString().c_str());
+
+ consumer_->asyncSendInterest(std::move(interest),
+ internal_signal_callback_.get());
+ }
+}
+
+void AsyncFullDuplexSocket::waitForSubscribers(AcceptCallback *cb) {
+ accept_callback_ = cb;
+}
+
+std::shared_ptr<core::ContentObject>
+AsyncFullDuplexSocket::decodeSynchronizationMessage(
+ const core::Interest &interest) {
+ auto mesg = interest.getPayload();
+ const MessageHeader *header =
+ reinterpret_cast<const MessageHeader *>(mesg.data());
+
+ switch (header->msg_type) {
+ case MessageType::ACTION: {
+ // Check what is the action to perform
+ const ActionMessage *message =
+ reinterpret_cast<const ActionMessage *>(header);
+
+ if (message->action == Action::SUBSCRIBE) {
+ // Add consumer to list on consumers to be notified
+ auto ret =
+ subscribers_.emplace(AF_INET6, (const uint8_t *)message->name, 0);
+ TRANSPORT_LOGI("Added subscriber %s :)", ret.first->toString().c_str());
+ if (ret.second) {
+ accept_callback_->connectionAccepted(*ret.first);
+ }
+
+ TRANSPORT_LOGI("Connection success!");
+
+ sync_notification_ = std::move(locator_.makeRandomName());
+ return createSubscriptionResponse(sync_notification_);
+
+ } else if (message->action == Action::CANCEL_SUBSCRIPTION) {
+ // XXX Modify name!!! Each allocated name allocates a 128 bit array.
+ subscribers_.erase(
+ core::Name(AF_INET6, (const uint8_t *)message->name, 0));
+ return createAck();
+ } else if (message->action == Action::SIGNAL_PRODUCTION) {
+ // trigger a reverse pull for the name contained in the message
+ core::Name n(AF_INET6, (const uint8_t *)message->name, 0);
+ std::cout << "PROD NOTIFICATION: Content to retrieve: " << n
+ << std::endl;
+ std::cout << "PROD NOTIFICATION: Interest name: " << interest.getName()
+ << std::endl; // << " compared to " << sync_notification_ <<
+ // std::endl;
+
+ if (sync_notification_.equals(interest.getName(), false)) {
+ std::cout << "Starting reverse pull for " << n << std::endl;
+ consumer_->asyncConsume(n, receive_buffer_);
+ return createAck();
+ }
+ } else {
+ TRANSPORT_LOGE("Received unknown message. Dropping it.");
+ }
+
+ break;
+ }
+ case MessageType::RESPONSE: {
+ throw errors::RuntimeException(
+ "The response should be a content object!!");
+ }
+ case MessageType::PAYLOAD: {
+ // The interest contains the payload directly.
+ // We saved one round trip :)
+
+ auto buffer = std::make_shared<utils::SharableVector<uint8_t>>();
+ const uint8_t *data = mesg.data() + sizeof(PayloadMessage);
+ buffer->assign(data, data + mesg.length() - sizeof(PayloadMessage));
+ read_callback_->readBufferAvailable(std::move(*buffer));
+ return createAck();
+ }
+ default: {
+ return std::shared_ptr<core::ContentObject>(nullptr);
+ }
+ }
+
+ return std::shared_ptr<core::ContentObject>(nullptr);
+}
+
+void AsyncFullDuplexSocket::onControlInterest(ProducerSocket &s,
+ const core::Interest &i) {
+ auto payload = i.getPayload();
+ if (payload.length()) {
+ // Try to decode payload and see if starting an async pull operation
+ auto response = decodeSynchronizationMessage(i);
+ if (response) {
+ response->setName(i.getName());
+ s.produce(*response);
+ }
+ }
+}
+
+void AsyncFullDuplexSocket::onContentProduced(ProducerSocket &producer,
+ const std::error_code &ec,
+ uint64_t bytes_written) {
+ if (write_callback_) {
+ if (!ec) {
+ write_callback_->writeSuccess();
+ } else {
+ write_callback_->writeErr(bytes_written);
+ }
+ }
+}
+
+void AsyncFullDuplexSocket::onContentRetrieved(ConsumerSocket &s,
+ std::size_t size,
+ const std::error_code &ec) {
+ // Sanity check
+ if (size != receive_buffer_->size()) {
+ TRANSPORT_LOGE(
+ "Received content size differs from size retrieved from the buffer.");
+ return;
+ }
+
+ TRANSPORT_LOGI("Received content with size %lu", size);
+ if (!ec) {
+ read_callback_->readBufferAvailable(std::move(*receive_buffer_));
+ } else {
+ TRANSPORT_LOGE("Error retrieving content.");
+ }
+ // consumer_->stop();
+}
+
+void AsyncFullDuplexSocket::OnConnectCallback::onContentObject(
+ core::Interest::Ptr &&, core::ContentObject::Ptr &&content_object) {
+ // The ack message should contain the name to be used for notifying
+ // the production of the content to the other part
+
+ if (content_object->getPayload().length() == 0) {
+ TRANSPORT_LOGW("Connection response message empty....");
+ return;
+ }
+
+ SubscriptionResponseMessage *response =
+ reinterpret_cast<SubscriptionResponseMessage *>(
+ content_object->getPayload().writableData());
+
+ if (response->response.header.msg_type == MessageType::RESPONSE) {
+ if (response->response.return_code == ReturnCode::OK) {
+ auto ret =
+ socket_.subscribers_.emplace(AF_INET6, (uint8_t *)response->name, 0);
+ TRANSPORT_LOGI("Successfully connected!!!! Subscriber added: %s",
+ ret.first->toString().c_str());
+ socket_.connect_callback_->connectSuccess();
+ }
+ }
+}
+
+void AsyncFullDuplexSocket::OnSignalCallback::onContentObject(
+ core::Interest::Ptr &&, core::ContentObject::Ptr &&content_object) {
+ return;
+}
+
+void AsyncFullDuplexSocket::OnSignalCallback::onTimeout(
+ core::Interest::Ptr &&interest) {
+ TRANSPORT_LOGE("Retransmitting signalization interest to %s!!",
+ interest->getName().toString().c_str());
+ socket_.consumer_->asyncSendInterest(std::move(interest),
+ socket_.internal_signal_callback_.get());
+}
+
+void AsyncFullDuplexSocket::OnConnectCallback::onTimeout(
+ core::Interest::Ptr &&interest) {
+ socket_.connect_callback_->connectErr(
+ std::make_error_code(std::errc::not_connected));
+}
+
+std::shared_ptr<core::ContentObject> AsyncFullDuplexSocket::createAck() {
+ // Send the response back
+ core::Name name("b001::abcd");
+ auto response = std::make_shared<core::ContentObject>(name);
+ auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+ _payload->append(sizeof(ResponseMessage));
+ auto payload = response->getPayload().data();
+ ResponseMessage *response_message = (ResponseMessage *)payload;
+ response_message->header.msg_type = MessageType::RESPONSE;
+ response_message->header.reserved[0] = 0;
+ response_message->header.reserved[1] = 0;
+ response_message->return_code = ReturnCode::OK;
+ response->appendPayload(std::move(_payload));
+ response->setLifetime(0);
+ return response;
+}
+
+std::shared_ptr<core::ContentObject>
+AsyncFullDuplexSocket::createSubscriptionResponse(const core::Name &name) {
+ // Send the response back
+ core::Name tmp_name("b001::abcd");
+ auto response = std::make_shared<core::ContentObject>(tmp_name);
+ auto _payload = utils::MemBuf::create(sizeof(SubscriptionResponseMessage));
+ _payload->append(sizeof(SubscriptionResponseMessage));
+ auto payload = _payload->data();
+ SubscriptionResponseMessage *response_message =
+ (SubscriptionResponseMessage *)payload;
+ response_message->response.header.msg_type = MessageType::RESPONSE;
+ response_message->response.header.reserved[0] = 0;
+ response_message->response.header.reserved[1] = 0;
+ response_message->response.return_code = ReturnCode::OK;
+ name.copyToDestination(reinterpret_cast<uint8_t *>(response_message->name));
+ response->appendPayload(std::move(_payload));
+ response->setLifetime(0);
+ return response;
+}
+
+} // namespace interface
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h
new file mode 100755
index 000000000..f881bea54
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+/*
+ * This class is created for sending/receiving data over an ICN network.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/interfaces/async_transport.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <unordered_set>
+#include <vector>
+
+namespace transport {
+
+namespace interface {
+
+enum class MessageType : uint8_t { ACTION, RESPONSE, PAYLOAD };
+
+enum class Action : uint8_t {
+ SUBSCRIBE,
+ CANCEL_SUBSCRIPTION,
+ SIGNAL_PRODUCTION,
+};
+
+enum class ReturnCode : uint8_t {
+ OK,
+ FAILED,
+};
+
+struct MessageHeader {
+ MessageType msg_type;
+ uint8_t reserved[2];
+};
+
+struct ActionMessage {
+ MessageHeader header;
+ Action action;
+ uint64_t name[2];
+};
+
+struct ResponseMessage {
+ MessageHeader header;
+ ReturnCode return_code;
+};
+
+struct SubscriptionResponseMessage {
+ ResponseMessage response;
+ uint64_t name[2];
+};
+
+struct PayloadMessage {
+ MessageHeader header;
+ uint8_t reserved[1];
+};
+
+// struct NotificationMessage {
+// Action action;
+// uint8_t reserved[3];
+// uint64_t
+// }
+
+using core::Prefix;
+
+class AsyncFullDuplexSocket : public AsyncSocket,
+ public AsyncReader,
+ public AsyncWriter,
+ public AsyncAcceptor {
+ private:
+ struct Counters {
+ uint64_t app_bytes_written_;
+ uint64_t app_bytes_read_;
+
+ TRANSPORT_ALWAYS_INLINE void updateBytesWritten(uint64_t bytes) {
+ app_bytes_written_ += bytes;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void updateBytesRead(uint64_t bytes) {
+ app_bytes_read_ += bytes;
+ }
+ };
+
+ public:
+ using UniquePtr = std::unique_ptr<AsyncFullDuplexSocket>;
+ using SharedPtr = std::unique_ptr<AsyncFullDuplexSocket>;
+
+ AsyncFullDuplexSocket(const Prefix &locator, asio::io_service &io_service);
+ AsyncFullDuplexSocket(const core::Prefix &locator);
+
+ ~AsyncFullDuplexSocket() {
+ TRANSPORT_LOGI("Adios AsyncFullDuplexSocket!!!");
+ };
+
+ using ReadCallback = AsyncReader::ReadCallback;
+ using WriteCallback = AsyncWriter::WriteCallback;
+
+ TRANSPORT_ALWAYS_INLINE void setReadCB(ReadCallback *callback) override {
+ read_callback_ = callback;
+ }
+
+ TRANSPORT_ALWAYS_INLINE ReadCallback *getReadCallback() const override {
+ return read_callback_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE void setWriteCB(WriteCallback *callback) override {
+ write_callback_ = callback;
+ }
+
+ TRANSPORT_ALWAYS_INLINE WriteCallback *getWriteCallback() const override {
+ return write_callback_;
+ }
+
+ TRANSPORT_ALWAYS_INLINE const core::Prefix &getLocator() { return locator_; }
+
+ void connect(ConnectCallback *callback, const core::Prefix &prefix) override;
+
+ void write(WriteCallback *callback, const void *buf, size_t bytes,
+ const PublicationOptions &options,
+ WriteFlags flags = WriteFlags::NONE) override;
+
+ virtual void write(WriteCallback *callback,
+ utils::SharableVector<uint8_t> &&output_buffer,
+ const PublicationOptions &options,
+ WriteFlags flags = WriteFlags::NONE) override;
+
+ void waitForSubscribers(AcceptCallback *cb) override;
+
+ // void writev(
+ // WriteCallback* callback,
+ // const iovec* vec,
+ // size_t count,
+ // Name &&content_to_publish_name,
+ // WriteFlags flags = WriteFlags::NONE) override;
+
+ void close() override;
+
+ void closeNow() override;
+
+ void shutdownWrite() override;
+
+ void shutdownWriteNow() override;
+
+ bool good() const override;
+
+ bool readable() const override;
+
+ bool writable() const override;
+
+ bool isPending() const override;
+
+ bool connected() const override;
+
+ bool error() const override;
+
+ void setSendTimeout(uint32_t milliseconds) override;
+
+ size_t getAppBytesWritten() const override;
+ size_t getRawBytesWritten() const override;
+ size_t getAppBytesReceived() const override;
+ size_t getRawBytesReceived() const override;
+
+ uint32_t getSendTimeout() const override;
+
+ private:
+ std::shared_ptr<core::ContentObject> decodeSynchronizationMessage(
+ const core::Interest &interest);
+
+ class OnConnectCallback : public BasePortal::ConsumerCallback {
+ public:
+ OnConnectCallback(AsyncFullDuplexSocket &socket) : socket_(socket){};
+ virtual ~OnConnectCallback() = default;
+ void onContentObject(core::Interest::Ptr &&,
+ core::ContentObject::Ptr &&content_object) override;
+ void onTimeout(core::Interest::Ptr &&interest) override;
+
+ private:
+ AsyncFullDuplexSocket &socket_;
+ };
+
+ class OnSignalCallback : public BasePortal::ConsumerCallback {
+ public:
+ OnSignalCallback(AsyncFullDuplexSocket &socket) : socket_(socket){};
+ virtual ~OnSignalCallback() = default;
+ void onContentObject(core::Interest::Ptr &&,
+ core::ContentObject::Ptr &&content_object);
+ void onTimeout(core::Interest::Ptr &&interest);
+
+ private:
+ AsyncFullDuplexSocket &socket_;
+ };
+
+ void onControlInterest(ProducerSocket &s, const core::Interest &i);
+ void onContentProduced(ProducerSocket &producer, const std::error_code &ec,
+ uint64_t bytes_written);
+ void onContentRetrieved(ConsumerSocket &s, std::size_t size,
+ const std::error_code &ec);
+
+ void signalProductionToSubscribers(const core::Name &name);
+ void piggybackPayloadToSubscribers(const core::Name &name,
+ const uint8_t *buffer, std::size_t bytes);
+
+ std::shared_ptr<core::ContentObject> createAck();
+ std::shared_ptr<core::ContentObject> createSubscriptionResponse(
+ const core::Name &name);
+
+ core::Prefix locator_;
+ uint32_t incremental_suffix_;
+ core::Name sync_notification_;
+ // std::unique_ptr<BasePortal> portal_;
+ asio::io_service internal_io_service_;
+ asio::io_service &io_service_;
+ asio::io_service::work work_;
+
+ // These names represent the "locator" of a certain
+ // peer that subscribed to this.
+ std::unordered_set<core::Name> subscribers_;
+
+ // Useful for publishing / Retrieving data
+ std::unique_ptr<ProducerSocket> producer_;
+ std::unique_ptr<ConsumerSocket> consumer_;
+
+ ReadCallback *read_callback_;
+ WriteCallback *write_callback_;
+ ConnectCallback *connect_callback_;
+ AcceptCallback *accept_callback_;
+
+ std::unique_ptr<OnConnectCallback> internal_connect_callback_;
+ std::unique_ptr<OnSignalCallback> internal_signal_callback_;
+
+ uint32_t send_timeout_milliseconds_;
+ struct Counters counters_;
+ std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer_;
+};
+
+} // namespace interface
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/publication_options.h b/libtransport/src/hicn/transport/interfaces/publication_options.h
new file mode 100755
index 000000000..ae5366ce7
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/publication_options.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace interface {
+
+class PublicationOptions {
+ public:
+ core::Name name;
+ uint32_t content_lifetime_milliseconds;
+ // TODO Signature
+};
+} // namespace interface
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc
new file mode 100755
index 000000000..de3e84417
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc
@@ -0,0 +1,35 @@
+/*
+ * 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/interfaces/rtc_socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+RTCConsumerSocket::RTCConsumerSocket(int protocol, asio::io_service &io_service)
+ : ConsumerSocket(protocol, io_service) {}
+
+RTCConsumerSocket::~RTCConsumerSocket() {}
+
+void RTCConsumerSocket::handleRTCPPacket(uint8_t *packet, size_t len) {
+ RTCTransportProtocol *transport = dynamic_cast<RTCTransportProtocol *>(
+ ConsumerSocket::transport_protocol_.get());
+ if (transport) transport->onRTCPPacket(packet, len);
+}
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h
new file mode 100755
index 000000000..86ccf6e22
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h
@@ -0,0 +1,35 @@
+/*
+ * 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/interfaces/socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+class RTCConsumerSocket : public ConsumerSocket {
+ public:
+ explicit RTCConsumerSocket(int protocol, asio::io_service &io_service);
+
+ ~RTCConsumerSocket();
+
+ void handleRTCPPacket(uint8_t *packet, size_t len);
+};
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
new file mode 100755
index 000000000..d8a9d53b9
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
@@ -0,0 +1,157 @@
+/*
+ * 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 <stdlib.h>
+#include <time.h>
+#include <hicn/transport/interfaces/rtc_socket_producer.h>
+
+#define NACK_HEADER_SIZE 8 // bytes
+#define TIMESTAMP_LEN 8 // bytes
+#define TCP_HEADER_SIZE 20
+#define IP6_HEADER_SIZE 40
+#define INIT_PACKET_PRODUCTION_RATE 100 // pps random value (almost 1Mbps)
+#define STATS_INTERVAL_DURATION 500 // ms
+#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8
+
+// NACK HEADER
+// +-----------------------------------------+
+// | 4 bytes: current segment in production |
+// +-----------------------------------------+
+// | 4 bytes: production rate (bytes x sec) |
+// +-----------------------------------------+
+// may require additional field (Rate for multiple qualities, ...)
+//
+
+namespace transport {
+
+namespace interface {
+
+RTCProducerSocket::RTCProducerSocket(asio::io_service &io_service)
+ : ProducerSocket(io_service),
+ currentSeg_(1),
+ nack_(std::make_shared<ContentObject>()),
+ producedBytes_(0),
+ producedPackets_(0),
+ bytesProductionRate_(0),
+ packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE),
+ perSecondFactor_(1000 / STATS_INTERVAL_DURATION) {
+ nack_->appendPayload(utils::MemBuf::create(NACK_HEADER_SIZE));
+ lastStats_ = std::chrono::steady_clock::now();
+ srand(time(NULL));
+ prodLabel_ = ((rand() % 255) << 24UL);
+}
+
+RTCProducerSocket::~RTCProducerSocket() {}
+
+void RTCProducerSocket::registerName(Prefix &producer_namespace) {
+ ProducerSocket::registerPrefix(producer_namespace);
+
+ flowName_ = producer_namespace.getName();
+
+ if (flowName_.getType() == HNT_CONTIGUOUS_V4 ||
+ flowName_.getType() == HNT_IOV_V4) {
+ headerSize_ = sizeof(hicn_v6_hdr_t::ip);
+ } else if (flowName_.getType() == HNT_CONTIGUOUS_V6 ||
+ flowName_.getType() == HNT_IOV_V6) {
+ headerSize_ = sizeof(hicn_v4_hdr_t::ip);
+ } else {
+ throw errors::RuntimeException("Unknown name format.");
+ }
+
+ headerSize_ += TCP_HEADER_SIZE;
+}
+
+void RTCProducerSocket::updateStats(uint32_t packet_size) {
+ producedBytes_ += packet_size;
+ producedPackets_++;
+ std::chrono::steady_clock::duration duration =
+ std::chrono::steady_clock::now() - lastStats_;
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() >=
+ STATS_INTERVAL_DURATION) {
+ lastStats_ = std::chrono::steady_clock::now();
+ bytesProductionRate_ = producedBytes_ * perSecondFactor_;
+ packetsProductionRate_ = producedPackets_ * perSecondFactor_;
+ producedBytes_ = 0;
+ producedPackets_ = 0;
+ }
+}
+
+void RTCProducerSocket::produce(const uint8_t *buf, size_t buffer_size) {
+ if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) {
+ return;
+ }
+
+ if (TRANSPORT_EXPECT_FALSE((buffer_size + headerSize_ + TIMESTAMP_LEN) >
+ data_packet_size_)) {
+ return;
+ }
+
+ updateStats(buffer_size + headerSize_ + TIMESTAMP_LEN);
+
+ std::shared_ptr<ContentObject> content_object =
+ std::make_shared<ContentObject>(flowName_.setSuffix(currentSeg_));
+ auto payload = utils::MemBuf::copyBuffer(buf, buffer_size, TIMESTAMP_LEN);
+
+ // content_object->setLifetime(content_object_expiry_time_);
+ content_object->setLifetime(1000); // XXX this should be set by the APP
+
+ uint64_t timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+
+ payload->prepend(TIMESTAMP_LEN);
+ uint8_t *payloadPointer = payload->writableData();
+ *(uint64_t *)payloadPointer = timestamp;
+ content_object->appendPayload(std::move(payload));
+
+ content_object->setPathLabel(prodLabel_);
+ portal_->sendContentObject(*content_object);
+
+ currentSeg_++;
+}
+
+void RTCProducerSocket::onInterest(Interest::Ptr &&interest) {
+ uint32_t interestSeg = interest->getName().getSuffix();
+ uint32_t lifetime = interest->getLifetime();
+ uint32_t max_gap;
+
+ // XXX
+ // packetsProductionRate_ is modified by another thread in updateStats
+ // this should be safe since I just read here. but, you never know.
+ max_gap =
+ floor((double)((double)((double)lifetime *
+ INTEREST_LIFETIME_REDUCTION_FACTOR / 1000.0) *
+ (double)packetsProductionRate_));
+
+ if (interestSeg < currentSeg_ || interestSeg > (max_gap + currentSeg_)) {
+ sendNack(*interest);
+ }
+ // else drop packet
+}
+
+void RTCProducerSocket::sendNack(const Interest &interest) {
+ nack_->setName(interest.getName());
+ uint32_t *payload_ptr = (uint32_t *)nack_->getPayload().data();
+ *payload_ptr = currentSeg_;
+ *(++payload_ptr) = bytesProductionRate_;
+
+ nack_->setLifetime(0);
+ nack_->setPathLabel(prodLabel_);
+ portal_->sendContentObject(*nack_);
+}
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
new file mode 100755
index 000000000..1a42bdc56
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
@@ -0,0 +1,60 @@
+/*
+ * 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/interfaces/socket_producer.h>
+#include <hicn/transport/utils/content_store.h>
+
+#include <map>
+#include <mutex>
+
+namespace transport {
+
+namespace interface {
+
+class RTCProducerSocket : public ProducerSocket {
+ public:
+ RTCProducerSocket(asio::io_service &io_service);
+ ~RTCProducerSocket();
+
+ void registerName(Prefix &producer_namespace);
+
+ void produce(const uint8_t *buffer, size_t buffer_size);
+
+ void onInterest(Interest::Ptr &&interest) override;
+
+ private:
+ void sendNack(const Interest &interest);
+ void updateStats(uint32_t packet_size);
+
+ // std::map<uint32_t, uint64_t> pendingInterests_;
+ uint32_t currentSeg_;
+ uint32_t prodLabel_;
+ uint16_t headerSize_;
+ Name flowName_;
+ // bool produceInSynch_;
+ std::shared_ptr<ContentObject> nack_;
+ uint32_t producedBytes_;
+ uint32_t producedPackets_;
+ uint32_t bytesProductionRate_;
+ uint32_t packetsProductionRate_;
+ uint32_t perSecondFactor_;
+ std::chrono::steady_clock::time_point lastStats_;
+};
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket.h b/libtransport/src/hicn/transport/interfaces/socket.h
new file mode 100755
index 000000000..22757810a
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket.h
@@ -0,0 +1,270 @@
+/*
+ * 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/facade.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/identity.h>
+#include <hicn/transport/utils/verifier.h>
+
+#define SOCKET_OPTION_GET 0
+#define SOCKET_OPTION_NOT_GET 1
+#define SOCKET_OPTION_SET 2
+#define SOCKET_OPTION_NOT_SET 3
+#define SOCKET_OPTION_DEFAULT 12345
+
+#define VOID_HANDLER 0
+
+namespace transport {
+
+namespace protocol {
+class IcnObserver;
+}
+
+namespace interface {
+
+template <typename PortalType>
+class Socket;
+class ConsumerSocket;
+class ProducerSocket;
+
+// using Interest = core::Interest;
+// using ContentObject = core::ContentObject;
+// using Name = core::Name;
+// using HashAlgorithm = core::HashAlgorithm;
+// using CryptoSuite = utils::CryptoSuite;
+// using Identity = utils::Identity;
+// using Verifier = utils::Verifier;
+
+using HicnForwarderPortal = core::HicnForwarderPortal;
+
+#ifdef __linux__
+#ifndef __ANDROID__
+using RawSocketPortal = core::RawSocketPortal;
+#endif
+#endif
+
+#ifdef __vpp__
+using VPPForwarderPortal = core::VPPForwarderPortal;
+using BaseSocket = Socket<VPPForwarderPortal>;
+using BasePortal = VPPForwarderPortal;
+#else
+using BaseSocket = Socket<HicnForwarderPortal>;
+using BasePortal = HicnForwarderPortal;
+#endif
+
+using PayloadType = core::PayloadType;
+using Prefix = core::Prefix;
+using Array = utils::Array<uint8_t>;
+
+using ConsumerInterestCallback =
+ std::function<void(ConsumerSocket &, const core::Interest &)>;
+
+using ConsumerContentCallback =
+ std::function<void(ConsumerSocket &, std::size_t, const std::error_code &)>;
+
+using ConsumerTimerCallback =
+ std::function<void(ConsumerSocket &, std::size_t,
+ std::chrono::milliseconds &, float, uint32_t, uint32_t)>;
+
+using ProducerContentCallback = std::function<void(
+ ProducerSocket &, const std::error_code &, uint64_t bytes_written)>;
+
+using ConsumerContentObjectCallback =
+ std::function<void(ConsumerSocket &, const core::ContentObject &)>;
+
+using ConsumerContentObjectVerificationCallback =
+ std::function<bool(ConsumerSocket &, const core::ContentObject &)>;
+
+using ConsumerManifestCallback =
+ std::function<void(ConsumerSocket &, const core::ContentObjectManifest &)>;
+
+using ProducerContentObjectCallback =
+ std::function<void(ProducerSocket &, core::ContentObject &)>;
+
+using ProducerInterestCallback =
+ std::function<void(ProducerSocket &, const core::Interest &)>;
+
+using ProducerInterestCallback =
+ std::function<void(ProducerSocket &, const core::Interest &)>;
+
+using namespace protocol;
+
+template <typename PortalType>
+class Socket {
+ static_assert(std::is_same<PortalType, HicnForwarderPortal>::value
+#ifdef __linux__
+#ifndef __ANDROID__
+ || std::is_same<PortalType, RawSocketPortal>::value
+#ifdef __vpp__
+ || std::is_same<PortalType, VPPForwarderPortal>::value
+#endif
+#endif
+ ,
+#else
+ ,
+
+#endif
+ "This class is not allowed as Portal");
+
+ public:
+ using Portal = PortalType;
+
+ virtual asio::io_service &getIoService() = 0;
+
+ virtual void connect() = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ double socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ bool socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ core::Name socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ProducerInterestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ProducerContentCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerInterestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerContentCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerManifestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ core::HashAlgorithm socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ const utils::Identity &socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ double &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ bool &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ core::Name &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ProducerInterestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ConsumerInterestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerContentCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ConsumerManifestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ProducerContentCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ core::HashAlgorithm &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ utils::Identity &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::string &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerTimerCallback &socket_option_value) = 0;
+
+ protected:
+ virtual ~Socket(){};
+
+ protected:
+ std::string output_interface_;
+};
+
+} // namespace interface
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
new file mode 100755
index 000000000..8109d0e99
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
@@ -0,0 +1,735 @@
+/*
+ * 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/interfaces/socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+ConsumerSocket::ConsumerSocket(int protocol)
+ : ConsumerSocket(protocol, internal_io_service_) {}
+
+ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service)
+ : io_service_(io_service),
+ portal_(std::make_shared<Portal>(io_service_)),
+ async_downloader_(),
+ interest_lifetime_(default_values::interest_lifetime),
+ min_window_size_(default_values::min_window_size),
+ max_window_size_(default_values::max_window_size),
+ current_window_size_(-1),
+ max_retransmissions_(
+ default_values::transport_protocol_max_retransmissions),
+ /****** RAAQM Parameters ******/
+ minimum_drop_probability_(default_values::minimum_drop_probability),
+ sample_number_(default_values::sample_number),
+ gamma_(default_values::gamma_value),
+ beta_(default_values::beta_value),
+ drop_factor_(default_values::drop_factor),
+ /****** END RAAQM Parameters ******/
+ rate_estimation_alpha_(default_values::rate_alpha),
+ rate_estimation_observer_(nullptr),
+ rate_estimation_choice_(0),
+ is_async_(false),
+ verify_signature_(false),
+ content_buffer_(nullptr),
+ on_interest_output_(VOID_HANDLER),
+ on_interest_timeout_(VOID_HANDLER),
+ on_interest_satisfied_(VOID_HANDLER),
+ on_content_object_input_(VOID_HANDLER),
+ on_content_object_verification_(VOID_HANDLER),
+ on_content_object_(VOID_HANDLER),
+ on_manifest_(VOID_HANDLER),
+ on_payload_retrieved_(VOID_HANDLER),
+ virtual_download_(false),
+ rtt_stats_(false),
+ timer_(portal_->getIoService()),
+ timer_interval_milliseconds_(0) {
+ switch (protocol) {
+ case TransportProtocolAlgorithms::VEGAS:
+ transport_protocol_ = std::make_shared<VegasTransportProtocol>(this);
+ break;
+ case TransportProtocolAlgorithms::CBR:
+ transport_protocol_ = std::make_shared<CbrTransportProtocol>(this);
+ break;
+ case TransportProtocolAlgorithms::RTC:
+ transport_protocol_ = std::make_shared<RTCTransportProtocol>(this);
+ break;
+ case TransportProtocolAlgorithms::RAAQM:
+ default:
+ transport_protocol_ = std::make_shared<RaaqmTransportProtocol>(this);
+ break;
+ }
+}
+
+ConsumerSocket::~ConsumerSocket() {
+ stop();
+
+ async_downloader_.stop();
+
+ transport_protocol_.reset();
+ portal_.reset();
+}
+
+void ConsumerSocket::connect() { portal_->connect(); }
+
+int ConsumerSocket::consume(const Name &name,
+ utils::SharableVector<uint8_t> &receive_buffer) {
+ if (transport_protocol_->isRunning()) {
+ return CONSUMER_BUSY;
+ }
+
+ content_buffer_ = receive_buffer.shared_from_this();
+
+ network_name_ = name;
+ network_name_.setSuffix(0);
+ is_async_ = false;
+
+ transport_protocol_->start(receive_buffer);
+
+ return CONSUMER_READY;
+}
+
+int ConsumerSocket::asyncConsume(
+ const Name &name,
+ std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer) {
+ // XXX Try to move the name here, instead of copying it!!
+ if (!async_downloader_.stopped()) {
+ async_downloader_.add([this, receive_buffer, name]() {
+ network_name_ = std::move(name);
+ network_name_.setSuffix(0);
+ is_async_ = true;
+ transport_protocol_->start(*receive_buffer);
+ });
+ }
+
+ return CONSUMER_READY;
+}
+
+void ConsumerSocket::asyncSendInterest(Interest::Ptr &&interest,
+ Portal::ConsumerCallback *callback) {
+ if (!async_downloader_.stopped()) {
+ // TODO Workaround, to be fixed!
+ auto i = interest.release();
+ async_downloader_.add([this, i, callback]() mutable {
+ Interest::Ptr _interest(i);
+ portal_->setConsumerCallback(callback);
+ portal_->sendInterest(std::move(_interest));
+ portal_->runEventsLoop();
+ });
+ }
+}
+
+void ConsumerSocket::stop() {
+ if (transport_protocol_->isRunning()) {
+ transport_protocol_->stop();
+ }
+
+ //is_running_ = false;
+}
+
+void ConsumerSocket::resume() {
+ if(!transport_protocol_->isRunning()){
+ transport_protocol_->resume();
+ }
+}
+
+asio::io_service &ConsumerSocket::getIoService() {
+ return portal_->getIoService();
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ double socket_option_value) {
+ switch (socket_option_key) {
+ case MIN_WINDOW_SIZE:
+ min_window_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case MAX_WINDOW_SIZE:
+ max_window_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case CURRENT_WINDOW_SIZE:
+ current_window_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GAMMA_VALUE:
+ gamma_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case BETA_VALUE:
+ beta_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case DROP_FACTOR:
+ drop_factor_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case MINIMUM_DROP_PROBABILITY:
+ minimum_drop_probability_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case RATE_ESTIMATION_ALPHA:
+ if (socket_option_value >= 0 && socket_option_value < 1) {
+ rate_estimation_alpha_ = socket_option_value;
+ } else {
+ rate_estimation_alpha_ = ALPHA;
+ }
+ return SOCKET_OPTION_SET;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+ input_buffer_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ output_buffer_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::MAX_INTEREST_RETX:
+ max_retransmissions_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::INTEREST_LIFETIME:
+ interest_lifetime_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_retransmission_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_timeout_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_satisfied_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_output_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_input_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_verification_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+ if (socket_option_value == VOID_HANDLER) {
+ on_payload_retrieved_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+ if (socket_option_value > 0) {
+ rate_estimation_batching_parameter_ = socket_option_value;
+ } else {
+ rate_estimation_batching_parameter_ = BATCH;
+ }
+ return SOCKET_OPTION_SET;
+
+ case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+ if (socket_option_value > 0) {
+ rate_estimation_choice_ = socket_option_value;
+ } else {
+ rate_estimation_choice_ = RATE_CHOICE;
+ }
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::TIMER_INTERVAL:
+ timer_interval_milliseconds_ = socket_option_value;
+ TRANSPORT_LOGD("Ok set %d", timer_interval_milliseconds_);
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ bool socket_option_value) {
+ switch (socket_option_key) {
+ case OtherOptions::VIRTUAL_DOWNLOAD:
+ virtual_download_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case RaaqmTransportOptions::RTT_STATS:
+ rtt_stats_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::VERIFY_SIGNATURE:
+ verify_signature_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ Name socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ network_name_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ on_content_object_input_ = socket_option_value;
+ ;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ProducerContentObjectCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ on_content_object_verification_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerInterestCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ on_interest_retransmission_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ on_interest_output_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ on_interest_timeout_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ on_interest_satisfied_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ProducerInterestCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerContentCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+ on_payload_retrieved_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerManifestCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::MANIFEST_INPUT:
+ on_manifest_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ProducerContentCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) {
+ if (socket_option_key == RateEstimationOptions::RATE_ESTIMATION_OBSERVER) {
+ rate_estimation_observer_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ }
+
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, const utils::Identity &socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::CERTIFICATE:
+ key_id_ = verifier_.addKeyFromCertificate(socket_option_value);
+
+ if (key_id_ != nullptr) {
+ return SOCKET_OPTION_SET;
+ }
+
+ break;
+
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ output_interface_ = socket_option_value;
+ portal_->setOutputInterface(output_interface_);
+ return SOCKET_OPTION_SET;
+ }
+
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::TIMER_EXPIRES:
+ on_timer_expires_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ }
+
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ double &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MIN_WINDOW_SIZE:
+ socket_option_value = min_window_size_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::MAX_WINDOW_SIZE:
+ socket_option_value = max_window_size_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::CURRENT_WINDOW_SIZE:
+ socket_option_value = current_window_size_;
+ return SOCKET_OPTION_GET;
+
+ // RAAQM parameters
+
+ case RaaqmTransportOptions::GAMMA_VALUE:
+ socket_option_value = gamma_;
+ return SOCKET_OPTION_GET;
+
+ case RaaqmTransportOptions::BETA_VALUE:
+ socket_option_value = beta_;
+ return SOCKET_OPTION_GET;
+
+ case RaaqmTransportOptions::DROP_FACTOR:
+ socket_option_value = drop_factor_;
+ return SOCKET_OPTION_GET;
+
+ case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY:
+ socket_option_value = minimum_drop_probability_;
+ return SOCKET_OPTION_GET;
+
+ case RateEstimationOptions::RATE_ESTIMATION_ALPHA:
+ socket_option_value = rate_estimation_alpha_;
+ return SOCKET_OPTION_GET;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+ socket_option_value = input_buffer_size_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ socket_option_value = output_buffer_size_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::MAX_INTEREST_RETX:
+ socket_option_value = max_retransmissions_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::INTEREST_LIFETIME:
+ socket_option_value = interest_lifetime_;
+ return SOCKET_OPTION_GET;
+
+ case RaaqmTransportOptions::SAMPLE_NUMBER:
+ socket_option_value = sample_number_;
+ return SOCKET_OPTION_GET;
+
+ case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+ socket_option_value = rate_estimation_batching_parameter_;
+ return SOCKET_OPTION_GET;
+
+ case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+ socket_option_value = rate_estimation_choice_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ bool &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::ASYNC_MODE:
+ socket_option_value = is_async_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::RUNNING:
+ socket_option_value = transport_protocol_->isRunning();
+ return SOCKET_OPTION_GET;
+
+ case OtherOptions::VIRTUAL_DOWNLOAD:
+ socket_option_value = virtual_download_;
+ return SOCKET_OPTION_GET;
+
+ case RaaqmTransportOptions::RTT_STATS:
+ socket_option_value = rtt_stats_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::VERIFY_SIGNATURE:
+ socket_option_value = verify_signature_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ Name &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ socket_option_value = network_name_;
+ return SOCKET_OPTION_GET;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ socket_option_value = on_content_object_input_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ProducerContentObjectCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ socket_option_value = on_content_object_verification_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerInterestCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ socket_option_value = on_interest_retransmission_;
+ return SOCKET_OPTION_GET;
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ socket_option_value = on_interest_output_;
+ return SOCKET_OPTION_GET;
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ socket_option_value = on_interest_timeout_;
+ return SOCKET_OPTION_GET;
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ socket_option_value = on_interest_satisfied_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ProducerInterestCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerContentCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+ socket_option_value = on_payload_retrieved_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerManifestCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::MANIFEST_INPUT:
+ socket_option_value = on_manifest_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+ switch (socket_option_key) {
+ case PORTAL:
+ socket_option_value = portal_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) {
+ if (socket_option_key == RATE_ESTIMATION_OBSERVER) {
+ *socket_option_value = (rate_estimation_observer_);
+ return SOCKET_OPTION_GET;
+ }
+
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ utils::Identity &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ProducerContentCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ socket_option_value = output_interface_;
+ return SOCKET_OPTION_GET;
+ }
+
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerTimerCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::TIMER_EXPIRES:
+ socket_option_value = on_timer_expires_;
+ return SOCKET_OPTION_GET;
+ }
+
+ return SOCKET_OPTION_NOT_GET;
+}
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.h b/libtransport/src/hicn/transport/interfaces/socket_consumer.h
new file mode 100755
index 000000000..9e309aae8
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_consumer.h
@@ -0,0 +1,259 @@
+/*
+ * 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/interfaces/socket.h>
+
+#include <hicn/transport/protocols/cbr.h>
+#include <hicn/transport/protocols/protocol.h>
+#include <hicn/transport/protocols/raaqm.h>
+#include <hicn/transport/protocols/rtc.h>
+#include <hicn/transport/protocols/vegas.h>
+
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#define CONSUMER_READY 0
+#define CONSUMER_BUSY 1
+
+namespace transport {
+
+namespace interface {
+
+class ConsumerSocket : public BaseSocket {
+ friend class protocol::TransportProtocol;
+ friend class protocol::VegasTransportProtocol;
+ friend class protocol::RaaqmTransportProtocol;
+ friend class protocol::CbrTransportProtocol;
+
+ public:
+ explicit ConsumerSocket(int protocol);
+ explicit ConsumerSocket(int protocol, asio::io_service &io_service);
+
+ ~ConsumerSocket();
+
+ void connect() override;
+
+ int consume(const Name &name, utils::SharableVector<uint8_t> &receive_buffer);
+
+ int asyncConsume(
+ const Name &name,
+ std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer);
+
+ void asyncSendInterest(Interest::Ptr &&interest,
+ Portal::ConsumerCallback *callback);
+
+ void stop();
+
+ void resume();
+
+ asio::io_service &getIoService() override;
+
+ int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ double socket_option_value) override;
+
+ int setSocketOption(int socket_option_key, bool socket_option_value) override;
+
+ int setSocketOption(int socket_option_key, Name socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerInterestCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ProducerInterestCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerContentCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerManifestCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ utils::CryptoSuite crypto_suite) override;
+
+ int setSocketOption(int socket_option_key,
+ const utils::Identity &crypto_suite) override;
+
+ int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ProducerContentCallback socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ double &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ bool &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ Name &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerInterestCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ProducerInterestCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerContentCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerManifestCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ utils::CryptoSuite &crypto_suite) override;
+
+ int getSocketOption(int socket_option_key,
+ utils::Identity &crypto_suite) override;
+
+ int getSocketOption(int socket_option_key,
+ std::string &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerTimerCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ProducerContentCallback &socket_option_value) override;
+
+ protected:
+ std::shared_ptr<TransportProtocol> transport_protocol_;
+
+ private:
+ // context inner state variables
+ asio::io_service internal_io_service_;
+ asio::io_service &io_service_;
+
+ std::shared_ptr<Portal> portal_;
+
+ utils::EventThread async_downloader_;
+
+ Name network_name_;
+
+ int interest_lifetime_;
+
+ double min_window_size_;
+ double max_window_size_;
+ double current_window_size_;
+ uint32_t max_retransmissions_;
+ size_t output_buffer_size_;
+ size_t input_buffer_size_;
+
+ // RAAQM Parameters
+
+ double minimum_drop_probability_;
+ unsigned int sample_number_;
+ double gamma_;
+ double beta_;
+ double drop_factor_;
+
+ // Rate estimation parameters
+ double rate_estimation_alpha_;
+ IcnObserver *rate_estimation_observer_;
+ int rate_estimation_batching_parameter_;
+ int rate_estimation_choice_;
+
+ bool is_async_;
+
+ utils::Verifier verifier_;
+ PARCKeyId *key_id_;
+ bool verify_signature_;
+
+ std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+
+ ConsumerInterestCallback on_interest_retransmission_;
+ ConsumerInterestCallback on_interest_output_;
+ ConsumerInterestCallback on_interest_timeout_;
+ ConsumerInterestCallback on_interest_satisfied_;
+
+ ConsumerContentObjectCallback on_content_object_input_;
+ ConsumerContentObjectVerificationCallback on_content_object_verification_;
+
+ ConsumerContentObjectCallback on_content_object_;
+ ConsumerManifestCallback on_manifest_;
+
+ ConsumerContentCallback on_payload_retrieved_;
+
+ ConsumerTimerCallback on_timer_expires_;
+
+ // Virtual download for traffic generator
+
+ bool virtual_download_;
+ bool rtt_stats_;
+
+ Time t0_;
+ Time t1_;
+ asio::steady_timer timer_;
+ uint32_t timer_interval_milliseconds_;
+};
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h
new file mode 100755
index 000000000..5fae1c484
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.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 <chrono>
+#include <cstdint>
+
+namespace transport {
+
+namespace interface {
+
+namespace default_values {
+
+const uint32_t interest_lifetime = 1001; // milliseconds
+const uint32_t content_object_expiry_time =
+ 0xffff; // milliseconds -> 50 seconds
+const uint32_t content_object_packet_size = 1500; // The ethernet MTU
+const uint32_t producer_socket_input_buffer_size = 150000; // Interests
+const uint32_t producer_socket_output_buffer_size = 150000; // Content Object
+const uint32_t log_2_default_buffer_size = 12;
+const uint32_t signature_size = 260; // bytes
+const uint32_t key_locator_size = 60; // bytes
+const uint32_t limit_guard = 80; // bytes
+const uint32_t min_window_size = 1; // Interests
+const uint32_t max_window_size = 128000; // Interests
+const uint32_t digest_size = 34; // bytes
+const uint32_t max_out_of_order_segments = 3; // content object
+const uint32_t never_expire_time = 0x0000ffff << 0x0f;
+
+// RAAQM
+const int sample_number = 30;
+const double gamma_value = 1;
+const double beta_value = 0.8;
+const double drop_factor = 0.2;
+const double minimum_drop_probability = 0.00001;
+const int path_id = 0;
+const double rate_alpha = 0.8;
+
+// Vegas
+const double alpha = 1 / 8;
+const double beta = 1 / 4;
+const uint16_t k = 4;
+const std::chrono::milliseconds clock_granularity =
+ std::chrono::milliseconds(100);
+
+// maximum allowed values
+const uint32_t transport_protocol_min_retransmissions = 0;
+const uint32_t transport_protocol_max_retransmissions = 128;
+const uint32_t max_content_object_size = 8096;
+
+} // namespace default_values
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
new file mode 100755
index 000000000..1afad2b48
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
@@ -0,0 +1,108 @@
+/*
+ * 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 interface {
+
+typedef enum {
+ RAAQM = 0,
+ VEGAS = 1,
+ CBR = 3,
+ RTC = 4,
+} TransportProtocolAlgorithms;
+
+typedef enum {
+ INPUT_BUFFER_SIZE = 101,
+ OUTPUT_BUFFER_SIZE = 102,
+ NETWORK_NAME = 103,
+ NAME_SUFFIX = 104,
+ MAX_INTEREST_RETX = 105,
+ DATA_PACKET_SIZE = 106,
+ INTEREST_LIFETIME = 107,
+ CONTENT_OBJECT_EXPIRY_TIME = 108,
+ KEY_LOCATOR = 110,
+ SIGNATURE_TYPE = 111,
+ MIN_WINDOW_SIZE = 112,
+ MAX_WINDOW_SIZE = 113,
+ CURRENT_WINDOW_SIZE = 114,
+ ASYNC_MODE = 115,
+ MAKE_MANIFEST = 116,
+ PORTAL = 117,
+ RUNNING = 118,
+ HASH_ALGORITHM = 119,
+ CRYPTO_SUITE = 120,
+ IDENTITY = 121,
+ CERTIFICATE = 122,
+ VERIFY_SIGNATURE = 123,
+ TIMER_INTERVAL = 124
+} GeneralTransportOptions;
+
+typedef enum {
+ SAMPLE_NUMBER = 201,
+ GAMMA_VALUE = 202,
+ BETA_VALUE = 203,
+ DROP_FACTOR = 204,
+ MINIMUM_DROP_PROBABILITY = 205,
+ PATH_ID = 206,
+ RTT_STATS = 207,
+} RaaqmTransportOptions;
+
+typedef enum {
+ RATE_ESTIMATION_ALPHA = 301,
+ RATE_ESTIMATION_OBSERVER = 302,
+ RATE_ESTIMATION_BATCH_PARAMETER = 303,
+ RATE_ESTIMATION_CHOICE = 304,
+} RateEstimationOptions;
+
+typedef enum {
+ INTEREST_OUTPUT = 401,
+ INTEREST_RETRANSMISSION = 402,
+ INTEREST_EXPIRED = 403,
+ INTEREST_SATISFIED = 404,
+ CONTENT_OBJECT_INPUT = 411,
+ MANIFEST_INPUT = 412,
+ CONTENT_OBJECT_TO_VERIFY = 413,
+ CONTENT_RETRIEVED = 414,
+ TIMER_EXPIRES = 415
+} ConsumerCallbacksOptions;
+
+typedef enum {
+ INTEREST_INPUT = 501,
+ INTEREST_DROP = 502,
+ INTEREST_PASS = 503,
+ CACHE_HIT = 506,
+ CACHE_MISS = 508,
+ NEW_CONTENT_OBJECT = 509,
+ CONTENT_OBJECT_SIGN = 513,
+ CONTENT_OBJECT_READY = 510,
+ CONTENT_OBJECT_OUTPUT = 511,
+ CONTENT_PRODUCED = 512
+} ProducerCallbacksOptions;
+
+typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions;
+
+typedef enum { VIRTUAL_DOWNLOAD = 601, USE_CFG_FILE = 603 } OtherOptions;
+
+typedef enum {
+ SHA_256 = 701,
+ RSA_256 = 702,
+} SignatureType;
+
+} // namespace interface
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.cc b/libtransport/src/hicn/transport/interfaces/socket_producer.cc
new file mode 100755
index 000000000..69adc2b3f
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_producer.cc
@@ -0,0 +1,948 @@
+/*
+ * 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/interfaces/socket_producer.h>
+
+namespace transport {
+
+namespace interface {
+
+typedef std::chrono::time_point<std::chrono::steady_clock> Time;
+typedef std::chrono::microseconds TimeDuration;
+
+ProducerSocket::ProducerSocket() : ProducerSocket(internal_io_service_) {}
+
+ProducerSocket::ProducerSocket(asio::io_service &io_service)
+ : io_service_(io_service),
+ portal_(std::make_shared<Portal>(io_service_)),
+ data_packet_size_(default_values::content_object_packet_size),
+ content_object_expiry_time_(default_values::content_object_expiry_time),
+ output_buffer_(default_values::producer_socket_output_buffer_size),
+ async_thread_(),
+ registration_status_(REGISTRATION_NOT_ATTEMPTED),
+ making_manifest_(false),
+ signature_type_(SHA_256),
+ hash_algorithm_(HashAlgorithm::SHA_256),
+ input_buffer_capacity_(default_values::producer_socket_input_buffer_size),
+ input_buffer_size_(0),
+ processing_thread_stop_(false),
+ listening_thread_stop_(false),
+ on_interest_input_(VOID_HANDLER),
+ on_interest_dropped_input_buffer_(VOID_HANDLER),
+ on_interest_inserted_input_buffer_(VOID_HANDLER),
+ on_interest_satisfied_output_buffer_(VOID_HANDLER),
+ on_interest_process_(VOID_HANDLER),
+ on_new_segment_(VOID_HANDLER),
+ on_content_object_to_sign_(VOID_HANDLER),
+ on_content_object_in_output_buffer_(VOID_HANDLER),
+ on_content_object_output_(VOID_HANDLER),
+ on_content_object_evicted_from_output_buffer_(VOID_HANDLER),
+ on_content_produced_(VOID_HANDLER) {
+ listening_thread_stop_ = false;
+}
+
+ProducerSocket::~ProducerSocket() {
+ TRANSPORT_LOGI("Destroying the ProducerSocket");
+ processing_thread_stop_ = true;
+ portal_->stopEventsLoop();
+
+ if (processing_thread_.joinable()) {
+ processing_thread_.join();
+ }
+
+ if (listening_thread_.joinable()) {
+ listening_thread_.join();
+ }
+}
+
+void ProducerSocket::connect() {
+ portal_->connect(false);
+ listening_thread_ = std::thread(std::bind(&ProducerSocket::listen, this));
+}
+
+void ProducerSocket::serveForever() {
+ if (listening_thread_.joinable()) {
+ listening_thread_.join();
+ }
+}
+
+void ProducerSocket::stop() {
+ TRANSPORT_LOGI("Calling stop for ProducerSocket");
+ portal_->killConnection();
+ portal_->stopEventsLoop();
+}
+
+void ProducerSocket::registerPrefix(const Prefix &producer_namespace) {
+ served_namespaces_.push_back(producer_namespace);
+}
+
+void ProducerSocket::listen() {
+ registration_status_ = REGISTRATION_IN_PROGRESS;
+ bool first = true;
+
+ for (core::Prefix &producer_namespace : served_namespaces_) {
+ if (first) {
+ core::BindConfig bind_config(producer_namespace, 1000);
+ portal_->bind(bind_config);
+ portal_->setProducerCallback(this);
+ first = !first;
+ } else {
+ portal_->registerRoute(producer_namespace);
+ }
+ }
+
+ portal_->runEventsLoop();
+}
+
+void ProducerSocket::passContentObjectToCallbacks(
+ const std::shared_ptr<ContentObject> &content_object) {
+ if (content_object) {
+ if (on_new_segment_ != VOID_HANDLER) {
+ on_new_segment_(*this, *content_object);
+ }
+
+ if (on_content_object_to_sign_ != VOID_HANDLER) {
+ on_content_object_to_sign_(*this, *content_object);
+ }
+
+ if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
+ on_content_object_in_output_buffer_(*this, *content_object);
+ }
+
+ output_buffer_.insert(content_object);
+
+ if (on_content_object_output_ != VOID_HANDLER) {
+ on_content_object_output_(*this, *content_object);
+ }
+
+#ifndef PUSH_API
+ std::unordered_map<Name, std::shared_ptr<const Interest>>::iterator it;
+
+ {
+ std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+ it = pending_interests_.find(content_object->getName());
+ }
+
+ if (it != pending_interests_.end()) {
+ content_object->setLocator(it->second->getLocator());
+ portal_->sendContentObject(*content_object);
+ std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+ pending_interests_.erase(it);
+ }
+#else
+ portal_->sendContentObject(*content_object);
+#endif
+ }
+}
+
+void ProducerSocket::produce(ContentObject &content_object) {
+ if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
+ on_content_object_in_output_buffer_(*this, content_object);
+ }
+
+ output_buffer_.insert(std::static_pointer_cast<ContentObject>(
+ content_object.shared_from_this()));
+
+ if (on_content_object_output_ != VOID_HANDLER) {
+ on_content_object_output_(*this, content_object);
+ }
+
+#ifndef PUSH_API
+ std::unordered_map<Name, std::shared_ptr<const Interest>>::iterator it;
+
+ {
+ std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+ it = pending_interests_.find(content_object.getName());
+ }
+
+ if (it != pending_interests_.end()) {
+ content_object.setLocator(it->second->getLocator());
+ portal_->sendContentObject(content_object);
+ std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+ pending_interests_.erase(it);
+ }
+#else
+ portal_->sendContentObject(content_object);
+#endif
+}
+
+uint32_t ProducerSocket::produce(Name content_name, const uint8_t *buf,
+ size_t buffer_size, bool is_last,
+ uint32_t start_offset) {
+ if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) {
+ return 0;
+ }
+
+ const std::size_t hash_size = 32;
+
+ int bytes_segmented = 0;
+ std::size_t header_size;
+ std::size_t manifest_header_size = 0;
+ std::size_t signature_length = 0;
+ std::uint32_t final_block_number = 0;
+
+ uint64_t free_space_for_content = 0;
+
+ core::Packet::Format format;
+
+ uint32_t current_segment = start_offset;
+ std::shared_ptr<ContentObjectManifest> manifest;
+ bool is_last_manifest = false;
+ std::unique_ptr<utils::CryptoHash> zero_hash;
+
+ // TODO Manifest may still be used for indexing
+ if (making_manifest_ && !identity_) {
+ throw errors::RuntimeException(
+ "Making manifests without setting producer identity. Aborting.");
+ }
+
+ core::Packet::Format hf_format = core::Packet::Format::HF_UNSPEC;
+ core::Packet::Format hf_format_ah = core::Packet::Format::HF_UNSPEC;
+ if (content_name.getType() == HNT_CONTIGUOUS_V4 ||
+ content_name.getType() == HNT_IOV_V4) {
+ hf_format = core::Packet::Format::HF_INET_TCP;
+ hf_format_ah = core::Packet::Format::HF_INET_TCP_AH;
+ } else if (content_name.getType() == HNT_CONTIGUOUS_V6 ||
+ content_name.getType() == HNT_IOV_V6) {
+ hf_format = core::Packet::Format::HF_INET6_TCP;
+ hf_format_ah = core::Packet::Format::HF_INET6_TCP_AH;
+ } else {
+ throw errors::RuntimeException("Unknown name format.");
+ }
+
+ format = hf_format;
+ if (making_manifest_) {
+ format = hf_format;
+ manifest_header_size = core::Packet::getHeaderSizeFromFormat(
+ hf_format_ah, identity_->getSignatureLength());
+ } else if (identity_) {
+ format = hf_format_ah;
+ signature_length = identity_->getSignatureLength();
+ }
+
+ header_size = core::Packet::getHeaderSizeFromFormat(format, signature_length);
+
+ free_space_for_content = data_packet_size_ - header_size;
+
+ uint32_t number_of_segments =
+ uint32_t(std::ceil(double(buffer_size) / double(free_space_for_content)));
+
+ if (free_space_for_content * number_of_segments < buffer_size) {
+ number_of_segments++;
+ }
+
+ if (making_manifest_) {
+ auto segment_in_manifest = static_cast<float>(
+ std::floor(double(data_packet_size_ - manifest_header_size -
+ ContentObjectManifest::getManifestHeaderSize()) /
+ (4.0 + 32.0)) -
+ 1.0);
+ auto number_of_manifests = static_cast<uint32_t>(
+ std::ceil(float(number_of_segments) / segment_in_manifest));
+ final_block_number = number_of_segments + number_of_manifests - 1;
+
+ manifest.reset(ContentObjectManifest::createManifest(
+ content_name.setSuffix(current_segment++),
+ core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
+ hash_algorithm_, is_last_manifest, content_name,
+ core::NextSegmentCalculationStrategy::INCREMENTAL,
+ identity_->getSignatureLength()));
+ manifest->setLifetime(content_object_expiry_time_);
+
+ if (is_last) {
+ manifest->setFinalBlockNumber(final_block_number);
+ } else {
+ manifest->setFinalBlockNumber(std::numeric_limits<uint32_t>::max());
+ }
+
+ uint8_t hash[hash_size];
+ std::memset(hash, 0, hash_size);
+ zero_hash = std::make_unique<utils::CryptoHash>(
+ hash, hash_size, static_cast<utils::CryptoHashType>(hash_algorithm_));
+ }
+
+ for (unsigned int packaged_segments = 0;
+ packaged_segments < number_of_segments; packaged_segments++) {
+ if (making_manifest_) {
+ if (manifest->estimateManifestSize(2) >
+ data_packet_size_ - manifest_header_size) {
+ // Add next manifest
+ manifest->addSuffixHash(current_segment, *zero_hash);
+
+ // Send the current manifest
+ manifest->encode();
+
+ identity_->getSigner().sign(*manifest);
+
+ passContentObjectToCallbacks(manifest);
+
+ // Create new manifest. The reference to the last manifest has been
+ // acquired in the passContentObjectToCallbacks function, so we can
+ // safely release this reference
+ manifest.reset(ContentObjectManifest::createManifest(
+ content_name.setSuffix(current_segment),
+ core::ManifestVersion::VERSION_1,
+ core::ManifestType::INLINE_MANIFEST, hash_algorithm_,
+ is_last_manifest, content_name,
+ core::NextSegmentCalculationStrategy::INCREMENTAL,
+ identity_->getSignatureLength()));
+ manifest->setLifetime(content_object_expiry_time_);
+ if (is_last) {
+ manifest->setFinalBlockNumber(final_block_number);
+ } else {
+ manifest->setFinalBlockNumber(std::numeric_limits<uint32_t>::max());
+ }
+ current_segment++;
+ }
+ }
+
+ auto content_object = std::make_shared<ContentObject>(
+ content_name.setSuffix(current_segment), format);
+ content_object->setLifetime(content_object_expiry_time_);
+
+ if (!making_manifest_ && identity_) {
+ content_object->setSignatureSize(signature_length);
+ }
+
+ if (packaged_segments == number_of_segments - 1) {
+ content_object->appendPayload(&buf[bytes_segmented],
+ buffer_size - bytes_segmented);
+ bytes_segmented += buffer_size - bytes_segmented;
+
+ if (is_last && making_manifest_) {
+ is_last_manifest = true;
+ } else if (is_last) {
+ content_object->setRst();
+ }
+
+ } else {
+ content_object->appendPayload(&buf[bytes_segmented],
+ free_space_for_content);
+ bytes_segmented += free_space_for_content;
+ }
+
+ if (making_manifest_) {
+ using namespace std::chrono_literals;
+ utils::CryptoHash hash = content_object->computeDigest(hash_algorithm_);
+ manifest->addSuffixHash(current_segment, hash);
+ } else if (identity_) {
+ identity_->getSigner().sign(*content_object);
+ }
+
+ current_segment++;
+ passContentObjectToCallbacks(content_object);
+ }
+
+ if (making_manifest_) {
+ if (is_last_manifest) {
+ manifest->setFinalManifest(is_last_manifest);
+ }
+ manifest->encode();
+ // Time t0 = std::chrono::steady_clock::now();
+ identity_->getSigner().sign(*manifest);
+ passContentObjectToCallbacks(manifest);
+ }
+
+ if (on_content_produced_ != VOID_HANDLER) {
+ on_content_produced_(*this, std::make_error_code(std::errc(0)),
+ buffer_size);
+ }
+
+ return current_segment;
+}
+
+void ProducerSocket::asyncProduce(ContentObject &content_object) {
+ if (!async_thread_.stopped()) {
+ // async_thread_.add(std::bind(&ProducerSocket::produce, this,
+ // content_object));
+ }
+}
+
+// void ProducerSocket::asyncProduce(const Name &suffix,
+// const uint8_t *buf,
+// size_t buffer_size,
+// AsyncProduceCallback && handler) {
+// if (!async_thread_.stopped()) {
+// async_thread_.add([this, buffer = buf, size = buffer_size, cb =
+// std::move(handler)] () {
+// uint64_t bytes_written = produce(suff, buffer, size, 0, false);
+// auto ec = std::make_errc(0);
+// cb(*this, ec, bytes_written);
+// });
+// }
+// }
+
+void ProducerSocket::asyncProduce(const Name &suffix, const uint8_t *buf,
+ size_t buffer_size) {
+ if (!async_thread_.stopped()) {
+ async_thread_.add(
+ [this, suff = suffix, buffer = buf, size = buffer_size]() {
+ produce(suff, buffer, size, true);
+ });
+ }
+}
+
+void ProducerSocket::asyncProduce(
+ const Name &suffix, utils::SharableVector<uint8_t> &&output_buffer) {
+ if (!async_thread_.stopped()) {
+ async_thread_.add(
+ [this, suff = suffix, buffer = std::move(output_buffer)]() {
+ TRANSPORT_LOGI("FOR REAL!!!!!! --> Producing content with name %s",
+ suff.toString().c_str());
+ produce(suff, &buffer[0], buffer.size(), true);
+ });
+ }
+}
+
+void ProducerSocket::onInterest(const Interest &interest) {
+ if (on_interest_input_ != VOID_HANDLER) {
+ on_interest_input_(*this, interest);
+ }
+
+ const std::shared_ptr<ContentObject> content_object =
+ output_buffer_.find(interest);
+
+ if (content_object) {
+ if (on_interest_satisfied_output_buffer_ != VOID_HANDLER) {
+ on_interest_satisfied_output_buffer_(*this, interest);
+ }
+
+ if (on_content_object_output_ != VOID_HANDLER) {
+ on_content_object_output_(*this, *content_object);
+ }
+
+ portal_->sendContentObject(*content_object);
+ } else {
+#ifndef PUSH_API
+ {
+ std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+ pending_interests_[interest.getName()] =
+ std::static_pointer_cast<const Interest>(interest.shared_from_this());
+ }
+#endif
+
+ if (on_interest_process_ != VOID_HANDLER) {
+ // external_io_service_.post([this, &interest] () {
+ on_interest_process_(*this, interest);
+ // });
+ }
+ }
+}
+
+asio::io_service &ProducerSocket::getIoService() { return io_service_; }
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::DATA_PACKET_SIZE:
+ if (socket_option_value < default_values::max_content_object_size &&
+ socket_option_value > 0) {
+ data_packet_size_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ } else {
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+ if (socket_option_value >= 1) {
+ input_buffer_capacity_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ } else {
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ output_buffer_.setLimit(socket_option_value);
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+ content_object_expiry_time_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case GeneralTransportOptions::SIGNATURE_TYPE:
+ if (socket_option_value == SOCKET_OPTION_DEFAULT) {
+ signature_type_ = SHA_256;
+ } else {
+ signature_type_ = socket_option_value;
+ }
+
+ if (signature_type_ == SHA_256 || signature_type_ == RSA_256) {
+ signature_size_ = 32;
+ }
+
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_input_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_dropped_input_buffer_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_inserted_input_buffer_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::CACHE_HIT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_satisfied_output_buffer_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::CACHE_MISS:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_process_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_new_segment_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_to_sign_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_in_output_buffer_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_output_ = VOID_HANDLER;
+ return SOCKET_OPTION_SET;
+ }
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ double socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ bool socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ making_manifest_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ Name socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ served_namespaces_ = socket_option_value;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerContentObjectCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ on_new_segment_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ on_content_object_to_sign_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ on_content_object_in_output_buffer_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ on_content_object_output_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerInterestCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ on_interest_input_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ on_interest_dropped_input_buffer_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ on_interest_inserted_input_buffer_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::CACHE_HIT:
+ on_interest_satisfied_output_buffer_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ case ProducerCallbacksOptions::CACHE_MISS:
+ on_interest_process_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerContentCallback socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::CONTENT_PRODUCED:
+ on_content_produced_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ConsumerInterestCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ConsumerContentCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ConsumerManifestCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ hash_algorithm_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::CRYPTO_SUITE:
+ crypto_suite_ = socket_option_value;
+ return SOCKET_OPTION_SET;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, const utils::Identity &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::IDENTITY:
+ identity_.reset();
+ identity_ = std::make_unique<utils::Identity>(socket_option_value);
+ return SOCKET_OPTION_SET;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ output_interface_ = socket_option_value;
+ portal_->setOutputInterface(output_interface_);
+ return SOCKET_OPTION_SET;
+ }
+
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key,
+ interface::ConsumerTimerCallback socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+ socket_option_value = input_buffer_capacity_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ socket_option_value = output_buffer_.getLimit();
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::DATA_PACKET_SIZE:
+ socket_option_value = data_packet_size_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+ socket_option_value = content_object_expiry_time_;
+ return SOCKET_OPTION_GET;
+
+ case GeneralTransportOptions::SIGNATURE_TYPE:
+ socket_option_value = signature_type_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ double &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ bool &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ socket_option_value = making_manifest_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ Name &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+
+ socket_option_value = served_namespaces_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ProducerContentObjectCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ socket_option_value = on_new_segment_;
+ return SOCKET_OPTION_GET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ socket_option_value = on_content_object_to_sign_;
+ return SOCKET_OPTION_GET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ socket_option_value = on_content_object_in_output_buffer_;
+ return SOCKET_OPTION_GET;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ socket_option_value = on_content_object_output_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ProducerContentCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::CONTENT_PRODUCED:
+ socket_option_value = on_content_produced_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ProducerInterestCallback &socket_option_value) {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ socket_option_value = on_interest_input_;
+ return SOCKET_OPTION_GET;
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ socket_option_value = on_interest_dropped_input_buffer_;
+ return SOCKET_OPTION_GET;
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ socket_option_value = on_interest_inserted_input_buffer_;
+ return SOCKET_OPTION_GET;
+
+ case CACHE_HIT:
+ socket_option_value = on_interest_satisfied_output_buffer_;
+ return SOCKET_OPTION_GET;
+
+ case CACHE_MISS:
+ socket_option_value = on_interest_process_;
+ return SOCKET_OPTION_GET;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ConsumerInterestCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ConsumerContentCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ConsumerManifestCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+ switch (socket_option_key) {
+ case PORTAL:
+ socket_option_value = portal_;
+ return SOCKET_OPTION_GET;
+ }
+
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ socket_option_value = hash_algorithm_;
+ return SOCKET_OPTION_GET;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ socket_option_value = crypto_suite_;
+ return SOCKET_OPTION_GET;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ utils::Identity &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::IDENTITY:
+ if (identity_) {
+ socket_option_value = *identity_;
+ return SOCKET_OPTION_SET;
+ }
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ socket_option_value = output_interface_;
+ return SOCKET_OPTION_GET;
+ }
+
+ return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key,
+ interface::ConsumerTimerCallback &socket_option_value) {
+ return SOCKET_OPTION_NOT_GET;
+}
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.h b/libtransport/src/hicn/transport/interfaces/socket_producer.h
new file mode 100755
index 000000000..06c47d973
--- /dev/null
+++ b/libtransport/src/hicn/transport/interfaces/socket_producer.h
@@ -0,0 +1,269 @@
+/*
+ * 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/interfaces/socket.h>
+#include <hicn/transport/utils/content_store.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <atomic>
+#include <cmath>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#define PUSH_API 1
+
+#define REGISTRATION_NOT_ATTEMPTED 0
+#define REGISTRATION_SUCCESS 1
+#define REGISTRATION_FAILURE 2
+#define REGISTRATION_IN_PROGRESS 3
+
+namespace transport {
+
+namespace interface {
+
+using namespace core;
+
+class ProducerSocket : public Socket<BasePortal>,
+ public BasePortal::ProducerCallback {
+ public:
+ explicit ProducerSocket();
+ explicit ProducerSocket(asio::io_service &io_service);
+
+ ~ProducerSocket();
+
+ void connect() override;
+
+ uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size,
+ bool is_last = true, uint32_t start_offset = 0);
+
+ void produce(ContentObject &content_object);
+
+ void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size);
+
+ void asyncProduce(const Name &suffix,
+ utils::SharableVector<uint8_t> &&output_buffer);
+
+ void asyncProduce(ContentObject &content_object);
+
+ void registerPrefix(const Prefix &producer_namespace);
+
+ void serveForever();
+
+ void stop();
+
+ asio::io_service &getIoService() override;
+
+ virtual void onInterest(const Interest &interest);
+
+ virtual void onInterest(Interest::Ptr &&interest) override {
+ onInterest(*interest);
+ };
+
+ int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ double socket_option_value) override;
+
+ int setSocketOption(int socket_option_key, bool socket_option_value) override;
+
+ int setSocketOption(int socket_option_key, Name socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ProducerInterestCallback socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) override;
+
+ int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerInterestCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerContentCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerManifestCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key, IcnObserver *obs) override;
+
+ int setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ const utils::Identity &socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) override;
+
+ int setSocketOption(int socket_option_key,
+ ProducerContentCallback socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ double &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ bool &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ Name &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ProducerInterestCallback &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) override;
+
+ int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerInterestCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerContentCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerManifestCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ utils::Identity &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ std::string &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ProducerContentCallback &socket_option_value) override;
+
+ int getSocketOption(int socket_option_key,
+ ConsumerTimerCallback &socket_option_value) override;
+
+ protected:
+ asio::io_service internal_io_service_;
+ asio::io_service &io_service_;
+ std::shared_ptr<Portal> portal_;
+ std::size_t data_packet_size_;
+ std::list<Prefix> served_namespaces_;
+ uint32_t content_object_expiry_time_;
+
+ // buffers
+ utils::ContentStore output_buffer_;
+
+ private:
+ utils::EventThread async_thread_;
+
+ int registration_status_;
+
+ bool making_manifest_;
+
+ // map for storing sequence numbers for several calls of the publish function
+ std::unordered_map<Name, std::unordered_map<int, uint32_t>> seq_number_map_;
+
+ int signature_type_;
+ int signature_size_;
+
+ HashAlgorithm hash_algorithm_;
+ utils::CryptoSuite crypto_suite_;
+ std::unique_ptr<utils::Identity> identity_;
+ // utils::Signer& signer_;
+
+ // buffers
+
+ std::queue<std::shared_ptr<const Interest>> input_buffer_;
+ std::atomic_size_t input_buffer_capacity_;
+ std::atomic_size_t input_buffer_size_;
+
+#ifndef PUSH_API
+ std::mutex pending_interests_mtx_;
+ std::unordered_map<Name, std::shared_ptr<const Interest>> pending_interests_;
+#endif
+
+ // threads
+ std::thread listening_thread_;
+ std::thread processing_thread_;
+ volatile bool processing_thread_stop_;
+ volatile bool listening_thread_stop_;
+
+ // callbacks
+ protected:
+ ProducerInterestCallback on_interest_input_;
+ ProducerInterestCallback on_interest_dropped_input_buffer_;
+ ProducerInterestCallback on_interest_inserted_input_buffer_;
+ ProducerInterestCallback on_interest_satisfied_output_buffer_;
+ ProducerInterestCallback on_interest_process_;
+
+ ProducerContentObjectCallback on_new_segment_;
+ ProducerContentObjectCallback on_content_object_to_sign_;
+ ProducerContentObjectCallback on_content_object_in_output_buffer_;
+ ProducerContentObjectCallback on_content_object_output_;
+ ProducerContentObjectCallback on_content_object_evicted_from_output_buffer_;
+
+ ProducerContentCallback on_content_produced_;
+
+ private:
+ void listen();
+
+ void passContentObjectToCallbacks(
+ const std::shared_ptr<ContentObject> &content_object);
+};
+
+} // namespace interface
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/portability/CMakeLists.txt b/libtransport/src/hicn/transport/portability/CMakeLists.txt
new file mode 100755
index 000000000..eee973c2d
--- /dev/null
+++ b/libtransport/src/hicn/transport/portability/CMakeLists.txt
@@ -0,0 +1,26 @@
+# 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}/c_portability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/portability.h
+)
+
+list(APPEND SOURCE_FILES
+ ""
+)
+
+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/portability/c_portability.h b/libtransport/src/hicn/transport/portability/c_portability.h
new file mode 100755
index 000000000..71e976a81
--- /dev/null
+++ b/libtransport/src/hicn/transport/portability/c_portability.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * 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
+
+// noinline
+#ifdef _MSC_VER
+#define TRANSPORT_NOINLINE __declspec(noinline)
+#elif defined(__clang__) || defined(__GNUC__)
+#define TRANSPORT_NOINLINE __attribute__((__noinline__))
+#else
+#define TRANSPORT_NOINLINE
+#endif
+
+// always inline
+#ifdef _MSC_VER
+#define TRANSPORT_ALWAYS_INLINE __forceinline
+#elif defined(__clang__) || defined(__GNUC__)
+#define TRANSPORT_ALWAYS_INLINE inline __attribute__((__always_inline__))
+#else
+#define TRANSPORT_ALWAYS_INLINE inline
+#endif \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/portability/portability.h b/libtransport/src/hicn/transport/portability/portability.h
new file mode 100755
index 000000000..7063e1822
--- /dev/null
+++ b/libtransport/src/hicn/transport/portability/portability.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * 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/c_portability.h>
+
+#include <string.h>
+#include <cstddef>
+
+namespace portability {
+
+constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
+constexpr bool big_endian_arch = !little_endian_arch;
+
+#if defined(__GNUC__)
+#define _TRANSPORT_GNU_DISABLE_WARNING(warning) #warning
+#define TRANSPORT_GNU_DISABLE_WARNING(warning) \
+ _Pragma(_TRANSPORT_GNU_DISABLE_WARNING(GCC diagnostic ignored warning))
+
+#ifdef __clang__
+#define TRANSPORT_CLANG_DISABLE_WARNING(warning) \
+ TRANSPORT_GNU_DISABLE_WARNING(warning)
+#define TRANSPORT_GCC_DISABLE_WARNING(warning)
+#else
+#define TRANSPORT_CLANG_DISABLE_WARNING(warning)
+#define TRANSPORT_GCC_DISABLE_WARNING(warning) \
+ TRANSPORT_GNU_DISABLE_WARNING(warning)
+#endif
+#endif
+
+} // namespace portability
diff --git a/libtransport/src/hicn/transport/protocols/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/CMakeLists.txt
new file mode 100755
index 000000000..1c3b76c24
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/CMakeLists.txt
@@ -0,0 +1,46 @@
+# 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}/rate_estimation.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/download_observer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/vegas.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/vegas_rto_estimator.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cbr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/vegas.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/protocol.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/vegas_rto_estimator.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/cbr.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc
+)
+
+set(TRANSPORT_CONFIG
+ ${CMAKE_CURRENT_SOURCE_DIR}/consumer.conf
+)
+
+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/protocols/cbr.cc b/libtransport/src/hicn/transport/protocols/cbr.cc
new file mode 100755
index 000000000..3da4819c3
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/cbr.cc
@@ -0,0 +1,47 @@
+/*
+ * 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/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/cbr.h>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+CbrTransportProtocol::CbrTransportProtocol(BaseSocket *icnet_socket)
+ : VegasTransportProtocol(icnet_socket) {}
+
+void CbrTransportProtocol::start(
+ utils::SharableVector<uint8_t> &receive_buffer) {
+ current_window_size_ = socket_->current_window_size_;
+ VegasTransportProtocol::start(receive_buffer);
+}
+
+void CbrTransportProtocol::changeInterestLifetime(uint64_t segment) { return; }
+
+void CbrTransportProtocol::increaseWindow() {}
+
+void CbrTransportProtocol::decreaseWindow() {}
+
+void CbrTransportProtocol::afterDataUnsatisfied(uint64_t segment) {}
+
+void CbrTransportProtocol::afterContentReception(
+ const Interest &interest, const ContentObject &content_object) {}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/cbr.h b/libtransport/src/hicn/transport/protocols/cbr.h
new file mode 100755
index 000000000..0a572292a
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/cbr.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/protocols/raaqm_data_path.h>
+#include <hicn/transport/protocols/rate_estimation.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+namespace transport {
+
+namespace protocol {
+
+class CbrTransportProtocol : public VegasTransportProtocol {
+ public:
+ CbrTransportProtocol(interface::BaseSocket *icnet_socket);
+
+ void start(utils::SharableVector<uint8_t> &receive_buffer) override;
+
+ private:
+ void afterContentReception(const Interest &interest,
+ const ContentObject &content_object) override;
+
+ void afterDataUnsatisfied(uint64_t segment) override;
+
+ void increaseWindow() override;
+
+ void decreaseWindow() override;
+
+ void changeInterestLifetime(uint64_t segment) override;
+};
+
+} // end namespace protocol
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/consumer.conf b/libtransport/src/hicn/transport/protocols/consumer.conf
new file mode 100755
index 000000000..1a366f32f
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/consumer.conf
@@ -0,0 +1,21 @@
+; this file contais the parameters for RAAQM
+autotune = no
+lifetime = 500
+retransmissions = 128
+beta = 0.99
+drop = 0.003
+beta_wifi_ = 0.99
+drop_wifi_ = 0.6
+beta_lte_ = 0.99
+drop_lte_ = 0.003
+wifi_delay_ = 200
+lte_delay_ = 9000
+
+alpha = 0.95
+batching_parameter = 200
+
+;Choice of rate estimator:
+;0 --> an estimation each $(batching_parameter) packets
+;1 --> an estimation "a la TCP", estimation at the end of the download of the segment
+
+rate_estimator = 0
diff --git a/libtransport/src/hicn/transport/protocols/download_observer.h b/libtransport/src/hicn/transport/protocols/download_observer.h
new file mode 100755
index 000000000..6d24fe6fd
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/download_observer.h
@@ -0,0 +1,32 @@
+/*
+ * 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 protocol {
+
+class IcnObserver {
+ public:
+ virtual ~IcnObserver(){};
+
+ virtual void notifyStats(double throughput) = 0;
+ virtual void notifyDownloadTime(double downloadTime) = 0;
+};
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/protocol.cc b/libtransport/src/hicn/transport/protocols/protocol.cc
new file mode 100755
index 000000000..ea4fd6dbf
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/protocol.cc
@@ -0,0 +1,45 @@
+/*
+ * 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/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/protocol.h>
+
+namespace transport {
+
+namespace protocol {
+
+TransportProtocol::TransportProtocol(interface::BaseSocket *icn_socket)
+ : socket_(dynamic_cast<interface::ConsumerSocket *>(icn_socket)),
+ is_running_(false),
+ interest_pool_() {
+ // Create pool of interests
+ increasePoolSize();
+}
+
+TransportProtocol::~TransportProtocol() {}
+
+void TransportProtocol::updatePortal() { portal_ = socket_->portal_; }
+
+bool TransportProtocol::isRunning() { return is_running_; }
+
+void TransportProtocol::increasePoolSize(std::size_t size) {
+ for (std::size_t i = 0; i < size; i++) {
+ interest_pool_.add(new Interest());
+ }
+}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/protocol.h b/libtransport/src/hicn/transport/protocols/protocol.h
new file mode 100755
index 000000000..56c57e025
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/protocol.h
@@ -0,0 +1,79 @@
+/*
+ * 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/interfaces/socket.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace core;
+
+class TransportProtocolCallback {
+ virtual void onContentObject(const core::Interest &interest,
+ const core::ContentObject &content_object) = 0;
+ virtual void onTimeout(const core::Interest &interest) = 0;
+};
+
+class TransportProtocol : public interface::BasePortal::ConsumerCallback {
+ static constexpr std::size_t interest_pool_size = 4096;
+
+ public:
+ TransportProtocol(interface::BaseSocket *icn_socket);
+
+ virtual ~TransportProtocol();
+
+ void updatePortal();
+
+ bool isRunning();
+
+ virtual void start(utils::SharableVector<uint8_t> &content_buffer) = 0;
+
+ virtual void stop() = 0;
+
+ virtual void resume() = 0;
+
+ protected:
+ virtual void increasePoolSize(std::size_t size = interest_pool_size);
+
+ TRANSPORT_ALWAYS_INLINE Interest::Ptr getInterest() {
+ auto result = interest_pool_.get();
+
+ while (TRANSPORT_EXPECT_FALSE(!result.first)) {
+ // Add packets to the pool
+ increasePoolSize();
+ result = interest_pool_.get();
+ }
+
+ return std::move(result.second);
+ }
+ // Consumer Callback
+ virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0;
+ virtual void onTimeout(Interest::Ptr &&i) = 0;
+
+ protected:
+ interface::ConsumerSocket *socket_;
+ std::shared_ptr<interface::BasePortal> portal_;
+ volatile bool is_running_;
+ utils::ObjectPool<Interest> interest_pool_;
+};
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm.cc b/libtransport/src/hicn/transport/protocols/raaqm.cc
new file mode 100755
index 000000000..cd22ecfdc
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/raaqm.cc
@@ -0,0 +1,416 @@
+/*
+ * 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/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/raaqm.h>
+
+#include <fstream>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RaaqmTransportProtocol::RaaqmTransportProtocol(BaseSocket *icnet_socket)
+ : VegasTransportProtocol(icnet_socket), rate_estimator_(NULL) {
+ init();
+}
+
+RaaqmTransportProtocol::~RaaqmTransportProtocol() {
+ if (this->rate_estimator_) {
+ delete this->rate_estimator_;
+ }
+}
+
+void RaaqmTransportProtocol::init() {
+ std::ifstream is(RAAQM_CONFIG_PATH);
+
+ std::string line;
+
+ socket_->beta_ = default_values::beta_value;
+ socket_->drop_factor_ = default_values::drop_factor;
+ socket_->interest_lifetime_ = default_values::interest_lifetime;
+ socket_->max_retransmissions_ =
+ default_values::transport_protocol_max_retransmissions;
+ raaqm_autotune_ = false;
+ default_beta_ = default_values::beta_value;
+ default_drop_ = default_values::drop_factor;
+ beta_wifi_ = default_values::beta_value;
+ drop_wifi_ = default_values::drop_factor;
+ beta_lte_ = default_values::beta_value;
+ drop_lte_ = default_values::drop_factor;
+ wifi_delay_ = 1000;
+ lte_delay_ = 15000;
+
+ if (!is) {
+ TRANSPORT_LOGW("WARNING: RAAQM parameters not found, set default values");
+ return;
+ }
+
+ while (getline(is, line)) {
+ std::string command;
+ std::istringstream line_s(line);
+
+ line_s >> command;
+
+ if (command == ";") {
+ continue;
+ }
+
+ if (command == "autotune") {
+ std::string tmp;
+ std::string val;
+ line_s >> tmp >> val;
+ if (val == "yes") {
+ raaqm_autotune_ = true;
+ } else {
+ raaqm_autotune_ = false;
+ }
+ continue;
+ }
+
+ if (command == "lifetime") {
+ std::string tmp;
+ uint32_t lifetime;
+ line_s >> tmp >> lifetime;
+ socket_->interest_lifetime_ = lifetime;
+ continue;
+ }
+
+ if (command == "retransmissions") {
+ std::string tmp;
+ uint32_t rtx;
+ line_s >> tmp >> rtx;
+ socket_->max_retransmissions_ = rtx;
+ continue;
+ }
+
+ if (command == "beta") {
+ std::string tmp;
+ line_s >> tmp >> default_beta_;
+ socket_->beta_ = default_beta_;
+ continue;
+ }
+
+ if (command == "drop") {
+ std::string tmp;
+ line_s >> tmp >> default_drop_;
+ socket_->drop_factor_ = default_drop_;
+ continue;
+ }
+
+ if (command == "beta_wifi_") {
+ std::string tmp;
+ line_s >> tmp >> beta_wifi_;
+ continue;
+ }
+
+ if (command == "drop_wifi_") {
+ std::string tmp;
+ line_s >> tmp >> drop_wifi_;
+ continue;
+ }
+
+ if (command == "beta_lte_") {
+ std::string tmp;
+ line_s >> tmp >> beta_lte_;
+ continue;
+ }
+
+ if (command == "drop_lte_") {
+ std::string tmp;
+ line_s >> tmp >> drop_lte_;
+ continue;
+ }
+
+ if (command == "wifi_delay_") {
+ std::string tmp;
+ line_s >> tmp >> wifi_delay_;
+ continue;
+ }
+
+ if (command == "lte_delay_") {
+ std::string tmp;
+ line_s >> tmp >> lte_delay_;
+ continue;
+ }
+ if (command == "alpha") {
+ std::string tmp;
+ double rate_alpha = 0.0;
+ line_s >> tmp >> rate_alpha;
+ socket_->rate_estimation_alpha_ = rate_alpha;
+ continue;
+ }
+
+ if (command == "batching_parameter") {
+ std::string tmp;
+ uint32_t batching_param = 0;
+ line_s >> tmp >> batching_param;
+ socket_->rate_estimation_batching_parameter_ = batching_param;
+ continue;
+ }
+
+ if (command == "rate_estimator") {
+ std::string tmp;
+ uint32_t choice_param = 0;
+ line_s >> tmp >> choice_param;
+ socket_->rate_estimation_choice_ = choice_param;
+ continue;
+ }
+ }
+ is.close();
+}
+
+void RaaqmTransportProtocol::start(
+ utils::SharableVector<uint8_t> &content_buffer) {
+ if (this->rate_estimator_) {
+ this->rate_estimator_->onStart();
+ }
+
+ if (!cur_path_) {
+ double drop_factor;
+ double minimum_drop_probability;
+ uint32_t sample_number;
+ uint32_t interest_lifetime;
+ // double beta;
+
+ drop_factor = socket_->drop_factor_;
+ minimum_drop_probability = socket_->minimum_drop_probability_;
+ sample_number = socket_->sample_number_;
+ interest_lifetime = socket_->interest_lifetime_;
+ // beta = socket_->beta_;
+
+ double alpha = 0.0;
+ uint32_t batching_param = 0;
+ uint32_t choice_param = 0;
+ alpha = socket_->rate_estimation_alpha_;
+ batching_param = socket_->rate_estimation_batching_parameter_;
+ choice_param = socket_->rate_estimation_choice_;
+
+ if (choice_param == 1) {
+ this->rate_estimator_ = new ALaTcpEstimator();
+ } else {
+ this->rate_estimator_ = new SimpleEstimator(alpha, batching_param);
+ }
+
+ this->rate_estimator_->observer_ = socket_->rate_estimation_observer_;
+
+ cur_path_ = std::make_shared<RaaqmDataPath>(
+ drop_factor, minimum_drop_probability, interest_lifetime * 1000,
+ sample_number);
+ path_table_[default_values::path_id] = cur_path_;
+ }
+
+ VegasTransportProtocol::start(content_buffer);
+}
+
+void RaaqmTransportProtocol::copyContent(const ContentObject &content_object) {
+ if (TRANSPORT_EXPECT_FALSE(
+ (content_object.getName().getSuffix() == final_block_number_) ||
+ !(is_running_))) {
+ this->rate_estimator_->onDownloadFinished();
+ }
+ VegasTransportProtocol::copyContent(content_object);
+}
+
+void RaaqmTransportProtocol::updatePathTable(
+ const ContentObject &content_object) {
+ uint32_t path_id = content_object.getPathLabel();
+
+ if (path_table_.find(path_id) == path_table_.end()) {
+ if (cur_path_) {
+ // Create a new path with some default param
+ if (path_table_.empty()) {
+ throw errors::RuntimeException(
+ "No path initialized for path table, error could be in default "
+ "path initialization.");
+ } else {
+ // Initiate the new path default param
+ std::shared_ptr<RaaqmDataPath> new_path =
+ std::make_shared<RaaqmDataPath>(
+ *(path_table_.at(default_values::path_id)));
+ // Insert the new path into hash table
+ path_table_[path_id] = new_path;
+ }
+ } else {
+ throw errors::RuntimeException(
+ "UNEXPECTED ERROR: when running,current path not found.");
+ }
+ }
+
+ cur_path_ = path_table_[path_id];
+
+ size_t header_size = content_object.headerSize();
+ size_t data_size = content_object.payloadSize();
+
+ // Update measurements for path
+ cur_path_->updateReceivedStats(header_size + data_size, data_size);
+}
+
+void RaaqmTransportProtocol::updateRtt(uint64_t segment) {
+ if (TRANSPORT_EXPECT_FALSE(!cur_path_)) {
+ throw std::runtime_error("ERROR: no current path found, exit");
+ } else {
+ std::chrono::microseconds rtt;
+
+ std::chrono::steady_clock::duration duration =
+ std::chrono::steady_clock::now() -
+ interest_timepoints_[segment & mask_];
+ rtt = std::chrono::duration_cast<std::chrono::microseconds>(duration);
+
+ if (this->rate_estimator_) {
+ this->rate_estimator_->onRttUpdate(rtt.count());
+ }
+ cur_path_->insertNewRtt(rtt.count());
+ cur_path_->smoothTimer();
+
+ if (cur_path_->newPropagationDelayAvailable()) {
+ check_drop_probability();
+ }
+ }
+}
+
+void RaaqmTransportProtocol::changeInterestLifetime(uint64_t segment) {
+ return;
+}
+
+void RaaqmTransportProtocol::check_drop_probability() {
+ if (!raaqm_autotune_) {
+ return;
+ }
+
+ unsigned int max_pd = 0;
+ std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>>::iterator it;
+ for (auto it = path_table_.begin(); it != path_table_.end(); ++it) {
+ if (it->second->getPropagationDelay() > max_pd &&
+ it->second->getPropagationDelay() != UINT_MAX &&
+ !it->second->isStale()) {
+ max_pd = it->second->getPropagationDelay();
+ }
+ }
+
+ double drop_prob = 0;
+ double beta = 0;
+ if (max_pd < wifi_delay_) { // only ethernet paths
+ drop_prob = default_drop_;
+ beta = default_beta_;
+ } else if (max_pd < lte_delay_) { // at least one wifi path
+ drop_prob = drop_wifi_;
+ beta = beta_wifi_;
+ } else { // at least one lte path
+ drop_prob = drop_lte_;
+ beta = beta_lte_;
+ }
+
+ double old_drop_prob = 0;
+ double old_beta = 0;
+ old_beta = socket_->beta_;
+ old_drop_prob = socket_->drop_factor_;
+
+ if (drop_prob == old_drop_prob && beta == old_beta) {
+ return;
+ }
+
+ socket_->beta_ = beta;
+ socket_->drop_factor_ = drop_prob;
+
+ for (it = path_table_.begin(); it != path_table_.end(); it++) {
+ it->second->setDropProb(drop_prob);
+ }
+}
+
+void RaaqmTransportProtocol::check_for_stale_paths() {
+ if (!raaqm_autotune_) {
+ return;
+ }
+
+ bool stale = false;
+ std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>>::iterator it;
+ for (it = path_table_.begin(); it != path_table_.end(); ++it) {
+ if (it->second->isStale()) {
+ stale = true;
+ break;
+ }
+ }
+ if (stale) {
+ check_drop_probability();
+ }
+}
+
+void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+ check_for_stale_paths();
+ VegasTransportProtocol::onTimeout(std::move(interest));
+}
+
+void RaaqmTransportProtocol::increaseWindow() {
+ double max_window_size = socket_->max_window_size_;
+ if (current_window_size_ < max_window_size) {
+ double gamma = socket_->gamma_;
+
+ current_window_size_ += gamma / current_window_size_;
+ socket_->current_window_size_ = current_window_size_;
+ }
+ this->rate_estimator_->onWindowIncrease(current_window_size_);
+}
+
+void RaaqmTransportProtocol::decreaseWindow() {
+ double min_window_size = socket_->min_window_size_;
+ if (current_window_size_ > min_window_size) {
+ double beta = socket_->beta_;
+
+ current_window_size_ = current_window_size_ * beta;
+ if (current_window_size_ < min_window_size) {
+ current_window_size_ = min_window_size;
+ }
+
+ socket_->current_window_size_ = current_window_size_;
+ }
+ this->rate_estimator_->onWindowDecrease(current_window_size_);
+}
+
+void RaaqmTransportProtocol::RAAQM() {
+ if (!cur_path_) {
+ throw errors::RuntimeException("ERROR: no current path found, exit");
+ exit(EXIT_FAILURE);
+ } else {
+ // Change drop probability according to RTT statistics
+ cur_path_->updateDropProb();
+
+ if (rand() % 10000 <= cur_path_->getDropProb() * 10000) {
+ decreaseWindow();
+ }
+ }
+}
+
+void RaaqmTransportProtocol::afterDataUnsatisfied(uint64_t segment) {
+ // Decrease the window because the timeout happened
+ decreaseWindow();
+}
+
+void RaaqmTransportProtocol::afterContentReception(
+ const Interest &interest, const ContentObject &content_object) {
+ updatePathTable(content_object);
+ increaseWindow();
+ updateRtt(interest.getName().getSuffix());
+ this->rate_estimator_->onDataReceived((int)content_object.payloadSize() +
+ content_object.headerSize());
+ // Set drop probablility and window size accordingly
+ RAAQM();
+}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm.h b/libtransport/src/hicn/transport/protocols/raaqm.h
new file mode 100755
index 000000000..6ca410251
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/raaqm.h
@@ -0,0 +1,94 @@
+/*
+ * 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/protocols/raaqm_data_path.h>
+#include <hicn/transport/protocols/rate_estimation.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+namespace transport {
+
+namespace protocol {
+
+class RaaqmTransportProtocol : public VegasTransportProtocol {
+ public:
+ RaaqmTransportProtocol(interface::BaseSocket *icnet_socket);
+
+ ~RaaqmTransportProtocol();
+
+ void start(utils::SharableVector<uint8_t> &content_buffer) override;
+
+ protected:
+ void copyContent(const ContentObject &content_object) override;
+
+ private:
+ void init();
+
+ void afterContentReception(const Interest &interest,
+ const ContentObject &content_object) override;
+
+ void afterDataUnsatisfied(uint64_t segment) override;
+
+ void increaseWindow() override;
+
+ void updateRtt(uint64_t segment);
+
+ void decreaseWindow() override;
+
+ void changeInterestLifetime(uint64_t segment) override;
+
+ void onTimeout(Interest::Ptr &&interest) override;
+
+ void RAAQM();
+
+ void updatePathTable(const ContentObject &content_object);
+
+ void check_drop_probability();
+
+ void check_for_stale_paths();
+
+ void printRtt();
+
+ /**
+ * Current download path
+ */
+ std::shared_ptr<RaaqmDataPath> cur_path_;
+
+ /**
+ * Hash table for path: each entry is a pair path ID(key) - path object
+ */
+ std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>> path_table_;
+
+ bool set_interest_filter_;
+ // for rate-estimation at packet level
+ IcnRateEstimator *rate_estimator_;
+
+ // params for autotuning
+ bool raaqm_autotune_;
+ double default_beta_;
+ double default_drop_;
+ double beta_wifi_;
+ double drop_wifi_;
+ double beta_lte_;
+ double drop_lte_;
+ unsigned int wifi_delay_;
+ unsigned int lte_delay_;
+};
+
+} // end namespace protocol
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc b/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc
new file mode 100755
index 000000000..f876cf4f8
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc
@@ -0,0 +1,158 @@
+/*
+ * 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/protocols/raaqm_data_path.h>
+
+namespace transport {
+
+namespace protocol {
+
+RaaqmDataPath::RaaqmDataPath(double drop_factor,
+ double minimum_drop_probability,
+ unsigned new_timer, unsigned int samples,
+ uint64_t new_rtt, uint64_t new_rtt_min,
+ uint64_t new_rtt_max, unsigned new_pd)
+
+ : drop_factor_(drop_factor),
+ minimum_drop_probability_(minimum_drop_probability),
+ timer_(new_timer),
+ samples_(samples),
+ rtt_(new_rtt),
+ rtt_min_(new_rtt_min),
+ rtt_max_(new_rtt_max),
+ prop_delay_(new_pd),
+ new_prop_delay_(false),
+ drop_prob_(0),
+ packets_received_(0),
+ last_packets_received_(0),
+ m_packets_bytes_received_(0),
+ last_packets_bytes_received_(0),
+ raw_data_bytes_received_(0),
+ last_raw_data_bytes_received_(0),
+ rtt_samples_(samples_),
+ average_rtt_(0),
+ alpha_(ALPHA) {
+ gettimeofday(&m_last_received_pkt_, 0);
+}
+
+RaaqmDataPath &RaaqmDataPath::insertNewRtt(uint64_t new_rtt) {
+ rtt_ = new_rtt;
+ rtt_samples_.pushBack(new_rtt);
+
+ rtt_max_ = rtt_samples_.rBegin();
+ rtt_min_ = rtt_samples_.begin();
+
+ if (rtt_min_ < prop_delay_) {
+ new_prop_delay_ = true;
+ prop_delay_ = rtt_min_;
+ }
+
+ gettimeofday(&m_last_received_pkt_, 0);
+
+ return *this;
+}
+
+RaaqmDataPath &RaaqmDataPath::updateReceivedStats(std::size_t packet_size,
+ std::size_t data_size) {
+ packets_received_++;
+ m_packets_bytes_received_ += packet_size;
+ raw_data_bytes_received_ += data_size;
+
+ return *this;
+}
+
+double RaaqmDataPath::getDropFactor() { return drop_factor_; }
+
+double RaaqmDataPath::getDropProb() { return drop_prob_; }
+
+RaaqmDataPath &RaaqmDataPath::setDropProb(double dropProb) {
+ drop_prob_ = dropProb;
+
+ return *this;
+}
+
+double RaaqmDataPath::getMinimumDropProbability() {
+ return minimum_drop_probability_;
+}
+
+double RaaqmDataPath::getTimer() { return timer_; }
+
+RaaqmDataPath &RaaqmDataPath::smoothTimer() {
+ timer_ = (1 - TIMEOUT_SMOOTHER) * timer_ +
+ (TIMEOUT_SMOOTHER)*rtt_ * (TIMEOUT_RATIO);
+
+ return *this;
+}
+
+double RaaqmDataPath::getRtt() { return rtt_; }
+
+double RaaqmDataPath::getAverageRtt() { return average_rtt_; }
+
+double RaaqmDataPath::getRttMax() { return rtt_max_; }
+
+double RaaqmDataPath::getRttMin() { return rtt_min_; }
+
+unsigned RaaqmDataPath::getSampleValue() { return samples_; }
+
+unsigned RaaqmDataPath::getRttQueueSize() {
+ return static_cast<unsigned>(rtt_samples_.size());
+}
+
+RaaqmDataPath &RaaqmDataPath::updateDropProb() {
+ drop_prob_ = 0.0;
+
+ if (getSampleValue() == getRttQueueSize()) {
+ if (rtt_max_ == rtt_min_) {
+ drop_prob_ = minimum_drop_probability_;
+ } else {
+ drop_prob_ = minimum_drop_probability_ +
+ drop_factor_ * (rtt_ - rtt_min_) / (rtt_max_ - rtt_min_);
+ }
+ }
+
+ return *this;
+}
+
+double RaaqmDataPath::getMicroSeconds(struct timeval &time) {
+ return (double)(time.tv_sec) * 1000000 + (double)(time.tv_usec);
+}
+
+void RaaqmDataPath::setAlpha(double alpha) {
+ if (alpha >= 0 && alpha <= 1) {
+ alpha_ = alpha;
+ }
+}
+
+bool RaaqmDataPath::newPropagationDelayAvailable() {
+ bool r = new_prop_delay_;
+ new_prop_delay_ = false;
+ return r;
+}
+
+unsigned int RaaqmDataPath::getPropagationDelay() { return prop_delay_; }
+
+bool RaaqmDataPath::isStale() {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ double time = getMicroSeconds(now) - getMicroSeconds(m_last_received_pkt_);
+ if (time > 2000000) {
+ return true;
+ }
+ return false;
+}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.h b/libtransport/src/hicn/transport/protocols/raaqm_data_path.h
new file mode 100755
index 000000000..6f63940c9
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/raaqm_data_path.h
@@ -0,0 +1,230 @@
+/*
+ * 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/utils/min_filter.h>
+
+#include <sys/time.h>
+#include <climits>
+#include <iostream>
+
+#define TIMEOUT_SMOOTHER 0.1
+#define TIMEOUT_RATIO 10
+#define ALPHA 0.8
+
+namespace transport {
+
+namespace protocol {
+
+class RaaqmDataPath {
+ public:
+ RaaqmDataPath(double drop_factor, double minimum_drop_probability,
+ unsigned new_timer, unsigned int samples,
+ uint64_t new_rtt = 1000, uint64_t new_rtt_min = 1000,
+ uint64_t new_rtt_max = 1000, unsigned new_pd = UINT_MAX);
+
+ public:
+ /*
+ * @brief Add a new RTT to the RTT queue of the path, check if RTT queue is
+ * full, and thus need overwrite. Also it maintains the validity of min and
+ * max of RTT.
+ * @param new_rtt is the value of the new RTT
+ */
+ RaaqmDataPath &insertNewRtt(uint64_t new_rtt);
+
+ /**
+ * @brief Update the path statistics
+ * @param packet_size the size of the packet received, including the ICN
+ * header
+ * @param data_size the size of the data received, without the ICN header
+ */
+ RaaqmDataPath &updateReceivedStats(std::size_t packet_size,
+ std::size_t data_size);
+
+ /**
+ * @brief Get the value of the drop factor parameter
+ */
+ double getDropFactor();
+
+ /**
+ * @brief Get the value of the drop probability
+ */
+ double getDropProb();
+
+ /**
+ * @brief Set the value pf the drop probability
+ * @param drop_prob is the value of the drop probability
+ */
+ RaaqmDataPath &setDropProb(double drop_prob);
+
+ /**
+ * @brief Get the minimum drop probability
+ */
+ double getMinimumDropProbability();
+
+ /**
+ * @brief Get last RTT
+ */
+ double getRtt();
+
+ /**
+ * @brief Get average RTT
+ */
+ double getAverageRtt();
+
+ /**
+ * @brief Get the current m_timer value
+ */
+ double getTimer();
+
+ /**
+ * @brief Smooth he value of the m_timer accordingly with the last RTT
+ * measured
+ */
+ RaaqmDataPath &smoothTimer();
+
+ /**
+ * @brief Get the maximum RTT among the last samples
+ */
+ double getRttMax();
+
+ /**
+ * @brief Get the minimum RTT among the last samples
+ */
+ double getRttMin();
+
+ /**
+ * @brief Get the number of saved samples
+ */
+ unsigned getSampleValue();
+
+ /**
+ * @brief Get the size og the RTT queue
+ */
+ unsigned getRttQueueSize();
+
+ /*
+ * @brief Change drop probability according to RTT statistics
+ * Invoked in RAAQM(), before control window size update.
+ */
+ RaaqmDataPath &updateDropProb();
+
+ /**
+ * @brief This function convert the time from struct timeval to its value in
+ * microseconds
+ */
+ static double getMicroSeconds(struct timeval &time);
+
+ void setAlpha(double alpha);
+
+ /**
+ * @brief Returns the smallest RTT registered so far for this path
+ */
+
+ unsigned int getPropagationDelay();
+
+ bool newPropagationDelayAvailable();
+
+ bool isStale();
+
+ private:
+ /**
+ * The value of the drop factor
+ */
+ double drop_factor_;
+
+ /**
+ * The minumum drop probability
+ */
+ double minimum_drop_probability_;
+
+ /**
+ * The timer, expressed in milliseconds
+ */
+ double timer_;
+
+ /**
+ * The number of samples to store for computing the protocol measurements
+ */
+ const unsigned int samples_;
+
+ /**
+ * The last, the minimum and the maximum value of the RTT (among the last
+ * m_samples samples)
+ */
+ uint64_t rtt_, rtt_min_, rtt_max_, prop_delay_;
+
+ bool new_prop_delay_;
+
+ /**
+ * The current drop probability
+ */
+ double drop_prob_;
+
+ /**
+ * The number of packets received in this path
+ */
+ intmax_t packets_received_;
+
+ /**
+ * The first packet received after the statistics print
+ */
+ intmax_t last_packets_received_;
+
+ /**
+ * Total number of bytes received including the ICN header
+ */
+ intmax_t m_packets_bytes_received_;
+
+ /**
+ * The amount of packet bytes received at the last path summary computation
+ */
+ intmax_t last_packets_bytes_received_;
+
+ /**
+ * Total number of bytes received without including the ICN header
+ */
+ intmax_t raw_data_bytes_received_;
+
+ /**
+ * The amount of raw dat bytes received at the last path summary computation
+ */
+ intmax_t last_raw_data_bytes_received_;
+
+ class byArrival;
+
+ class byOrder;
+
+ /**
+ * Double ended queue for the RTTs
+ */
+
+ typedef utils::MinFilter<uint64_t> RTTQueue;
+
+ RTTQueue rtt_samples_;
+
+ /**
+ * Time of the last call to the path reporter method
+ */
+ struct timeval m_last_received_pkt_;
+
+ double average_rtt_;
+ double alpha_;
+};
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.cc b/libtransport/src/hicn/transport/protocols/rate_estimation.cc
new file mode 100755
index 000000000..e313bf9f6
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rate_estimation.cc
@@ -0,0 +1,353 @@
+/*
+ * 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/protocols/rate_estimation.h>
+#include <hicn/transport/utils/log.h>
+
+namespace transport {
+
+namespace protocol {
+
+void *Timer(void *data) {
+ InterRttEstimator *estimator = (InterRttEstimator *)data;
+
+ double dat_rtt, my_avg_win, my_avg_rtt;
+ int my_win_change, number_of_packets, max_packet_size;
+
+ pthread_mutex_lock(&(estimator->mutex_));
+ dat_rtt = estimator->rtt_;
+ pthread_mutex_unlock(&(estimator->mutex_));
+
+ while (estimator->is_running_) {
+ usleep(KV * dat_rtt);
+
+ pthread_mutex_lock(&(estimator->mutex_));
+
+ dat_rtt = estimator->rtt_;
+ my_avg_win = estimator->avg_win_;
+ my_avg_rtt = estimator->avg_rtt_;
+ my_win_change = estimator->win_change_;
+ number_of_packets = estimator->number_of_packets_;
+ max_packet_size = estimator->max_packet_size_;
+ estimator->avg_rtt_ = estimator->rtt_;
+ estimator->avg_win_ = 0;
+ estimator->win_change_ = 0;
+ estimator->number_of_packets_ = 1;
+
+ pthread_mutex_unlock(&(estimator->mutex_));
+
+ if (number_of_packets == 0 || my_win_change == 0) {
+ continue;
+ }
+ if (estimator->estimation_ == 0) {
+ estimator->estimation_ = (my_avg_win * 8.0 * max_packet_size * 1000000.0 /
+ (1.0 * my_win_change)) /
+ (my_avg_rtt / (1.0 * number_of_packets));
+ }
+
+ estimator->estimation_ =
+ estimator->alpha_ * estimator->estimation_ +
+ (1 - estimator->alpha_) * ((my_avg_win * 8.0 * max_packet_size *
+ 1000000.0 / (1.0 * my_win_change)) /
+ (my_avg_rtt / (1.0 * number_of_packets)));
+
+ if (estimator->observer_) {
+ estimator->observer_->notifyStats(estimator->estimation_);
+ }
+ }
+
+ return nullptr;
+}
+
+InterRttEstimator::InterRttEstimator(double alpha_arg) {
+ this->estimated_ = false;
+ this->observer_ = NULL;
+ this->alpha_ = alpha_arg;
+ this->thread_is_running_ = false;
+ this->my_th_ = NULL;
+ this->is_running_ = true;
+ this->avg_rtt_ = 0.0;
+ this->estimation_ = 0.0;
+ this->avg_win_ = 0.0;
+ this->rtt_ = 0.0;
+ this->win_change_ = 0;
+ this->number_of_packets_ = 0;
+ this->max_packet_size_ = 0;
+ this->win_current_ = 1.0;
+
+ pthread_mutex_init(&(this->mutex_), NULL);
+ gettimeofday(&(this->start_time_), 0);
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+InterRttEstimator::~InterRttEstimator() {
+ this->is_running_ = false;
+ if (this->my_th_) {
+ pthread_join(*(this->my_th_), NULL);
+ }
+ this->my_th_ = NULL;
+ pthread_mutex_destroy(&(this->mutex_));
+}
+
+void InterRttEstimator::onRttUpdate(double rtt) {
+ pthread_mutex_lock(&(this->mutex_));
+ this->rtt_ = rtt;
+ this->number_of_packets_++;
+ this->avg_rtt_ += rtt;
+ pthread_mutex_unlock(&(this->mutex_));
+
+ if (!thread_is_running_) {
+ my_th_ = (pthread_t *)malloc(sizeof(pthread_t));
+ if (!my_th_) {
+ TRANSPORT_LOGE("Error allocating thread.");
+ my_th_ = NULL;
+ }
+ if (/*int err = */ pthread_create(my_th_, NULL, transport::protocol::Timer,
+ (void *)this)) {
+ TRANSPORT_LOGE("Error creating the thread");
+ my_th_ = NULL;
+ }
+ thread_is_running_ = true;
+ }
+}
+
+void InterRttEstimator::onWindowIncrease(double win_current) {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+
+ pthread_mutex_lock(&(this->mutex_));
+ this->avg_win_ += this->win_current_ * delay;
+ this->win_current_ = win_current;
+ this->win_change_ += delay;
+ pthread_mutex_unlock(&(this->mutex_));
+
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+void InterRttEstimator::onWindowDecrease(double win_current) {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+
+ pthread_mutex_lock(&(this->mutex_));
+ this->avg_win_ += this->win_current_ * delay;
+ this->win_current_ = win_current;
+ this->win_change_ += delay;
+ pthread_mutex_unlock(&(this->mutex_));
+
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+ALaTcpEstimator::ALaTcpEstimator() {
+ this->estimation_ = 0.0;
+ this->observer_ = NULL;
+ gettimeofday(&(this->start_time_), 0);
+ this->totalSize_ = 0.0;
+}
+
+void ALaTcpEstimator::onStart() {
+ this->totalSize_ = 0.0;
+ gettimeofday(&(this->start_time_), 0);
+}
+
+void ALaTcpEstimator::onDownloadFinished() {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->start_time_);
+ this->estimation_ = this->totalSize_ * 8 * 1000000 / delay;
+ if (observer_) {
+ observer_->notifyStats(this->estimation_);
+ }
+}
+
+void ALaTcpEstimator::onDataReceived(int packet_size) {
+ this->totalSize_ += packet_size;
+}
+
+SimpleEstimator::SimpleEstimator(double alphaArg, int batching_param) {
+ this->estimation_ = 0.0;
+ this->estimated_ = false;
+ this->observer_ = NULL;
+ this->batching_param_ = batching_param;
+ this->total_size_ = 0.0;
+ this->number_of_packets_ = 0;
+ this->base_alpha_ = alphaArg;
+ this->alpha_ = alphaArg;
+ gettimeofday(&(this->start_time_), 0);
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+void SimpleEstimator::onStart() {
+ this->estimated_ = false;
+ this->number_of_packets_ = 0;
+ this->total_size_ = 0.0;
+ gettimeofday(&(this->begin_batch_), 0);
+ gettimeofday(&(this->start_time_), 0);
+}
+
+void SimpleEstimator::onDownloadFinished() {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->start_time_);
+ if (observer_) {
+ observer_->notifyDownloadTime(delay);
+ }
+ if (!this->estimated_) {
+ // Assuming all packets carry max_packet_size_ bytes of data
+ // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+ if (this->estimation_) {
+ this->estimation_ =
+ alpha_ * this->estimation_ +
+ (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+ } else {
+ this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+ }
+ if (observer_) {
+ observer_->notifyStats(this->estimation_);
+ }
+ this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) /
+ ((double)this->batching_param_));
+ } else {
+ if (this->number_of_packets_ >=
+ (int)(75.0 * (double)this->batching_param_ / 100.0)) {
+ delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+ // Assuming all packets carry max_packet_size_ bytes of data
+ // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+ if (this->estimation_) {
+ this->estimation_ =
+ alpha_ * this->estimation_ +
+ (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+ } else {
+ this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+ }
+ if (observer_) {
+ observer_->notifyStats(this->estimation_);
+ }
+ this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) /
+ ((double)this->batching_param_));
+ }
+ }
+ this->number_of_packets_ = 0;
+ this->total_size_ = 0.0;
+ gettimeofday(&(this->begin_batch_), 0);
+ gettimeofday(&(this->start_time_), 0);
+}
+
+void SimpleEstimator::onDataReceived(int packet_size) {
+ this->total_size_ += packet_size;
+}
+
+void SimpleEstimator::onRttUpdate(double rtt) {
+ this->number_of_packets_++;
+
+ if (number_of_packets_ == this->batching_param_) {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+ // Assuming all packets carry max_packet_size_ bytes of data
+ // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+ if (this->estimation_) {
+ this->estimation_ =
+ alpha_ * this->estimation_ +
+ (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+ } else {
+ this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+ }
+ if (observer_) {
+ observer_->notifyStats(this->estimation_);
+ }
+ this->alpha_ = this->base_alpha_;
+ this->number_of_packets_ = 0;
+ this->total_size_ = 0.0;
+ gettimeofday(&(this->begin_batch_), 0);
+ }
+}
+
+BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg,
+ int param) {
+ this->estimated_ = false;
+ this->observer_ = NULL;
+ this->alpha_ = alpha_arg;
+ this->batching_param_ = param;
+ this->number_of_packets_ = 0;
+ this->avg_win_ = 0.0;
+ this->avg_rtt_ = 0.0;
+ this->win_change_ = 0.0;
+ this->max_packet_size_ = 0;
+ this->estimation_ = 0.0;
+ this->win_current_ = 1.0;
+ gettimeofday(&(this->begin_batch_), 0);
+ gettimeofday(&(this->start_time_), 0);
+}
+
+void BatchingPacketsEstimator::onRttUpdate(double rtt) {
+ this->number_of_packets_++;
+ this->avg_rtt_ += rtt;
+
+ if (number_of_packets_ == this->batching_param_) {
+ if (estimation_ == 0) {
+ estimation_ = (avg_win_ * 8.0 * max_packet_size_ * 1000000.0 /
+ (1.0 * win_change_)) /
+ (avg_rtt_ / (1.0 * number_of_packets_));
+ } else {
+ estimation_ = alpha_ * estimation_ +
+ (1 - alpha_) * ((avg_win_ * 8.0 * max_packet_size_ *
+ 1000000.0 / (1.0 * win_change_)) /
+ (avg_rtt_ / (1.0 * number_of_packets_)));
+ }
+
+ if (observer_) {
+ observer_->notifyStats(estimation_);
+ }
+
+ this->number_of_packets_ = 0;
+ this->avg_win_ = 0.0;
+ this->avg_rtt_ = 0.0;
+ this->win_change_ = 0.0;
+ }
+}
+
+void BatchingPacketsEstimator::onWindowIncrease(double win_current) {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+ this->avg_win_ += this->win_current_ * delay;
+ this->win_current_ = win_current;
+ this->win_change_ += delay;
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+void BatchingPacketsEstimator::onWindowDecrease(double win_current) {
+ timeval end;
+ gettimeofday(&end, 0);
+ double delay = RaaqmDataPath::getMicroSeconds(end) -
+ RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+ this->avg_win_ += this->win_current_ * delay;
+ this->win_current_ = win_current;
+ this->win_change_ += delay;
+ gettimeofday(&(this->begin_batch_), 0);
+}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.h b/libtransport/src/hicn/transport/protocols/rate_estimation.h
new file mode 100755
index 000000000..b889efe12
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rate_estimation.h
@@ -0,0 +1,175 @@
+/*
+ * 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 <unistd.h>
+
+#include <hicn/transport/protocols/download_observer.h>
+#include <hicn/transport/protocols/raaqm_data_path.h>
+
+#define BATCH 50
+#define KV 20
+#define ALPHA 0.8
+#define RATE_CHOICE 0
+
+namespace transport {
+
+namespace protocol {
+
+class IcnRateEstimator {
+ public:
+ IcnRateEstimator(){};
+
+ virtual ~IcnRateEstimator(){};
+
+ virtual void onRttUpdate(double rtt){};
+
+ virtual void onDataReceived(int packetSize){};
+
+ virtual void onWindowIncrease(double winCurrent){};
+
+ virtual void onWindowDecrease(double winCurrent){};
+
+ virtual void onStart(){};
+
+ virtual void onDownloadFinished(){};
+
+ virtual void setObserver(IcnObserver *observer) {
+ this->observer_ = observer;
+ };
+ IcnObserver *observer_;
+ struct timeval start_time_;
+ struct timeval begin_batch_;
+ double base_alpha_;
+ double alpha_;
+ double estimation_;
+ int number_of_packets_;
+ // this boolean is to make sure at least one estimation of the BW is done
+ bool estimated_;
+};
+
+// A rate estimator RTT-based. Computes EWMA(WinSize)/EWMA(RTT)
+
+class InterRttEstimator : public IcnRateEstimator {
+ public:
+ InterRttEstimator(double alpha_arg);
+
+ ~InterRttEstimator();
+
+ void onRttUpdate(double rtt);
+
+ void onDataReceived(int packet_size) {
+ if (packet_size > this->max_packet_size_) {
+ this->max_packet_size_ = packet_size;
+ }
+ };
+
+ void onWindowIncrease(double win_current);
+
+ void onWindowDecrease(double win_current);
+
+ void onStart(){};
+
+ void onDownloadFinished(){};
+
+ // private: should be done by using getters
+ pthread_t *my_th_;
+ bool thread_is_running_;
+ double rtt_;
+ bool is_running_;
+ pthread_mutex_t mutex_;
+ double avg_rtt_;
+ double avg_win_;
+ int max_packet_size_;
+ double win_change_;
+ double win_current_;
+};
+
+// A rate estimator, Batching Packets based. Computes EWMA(WinSize)/EWMA(RTT)
+
+class BatchingPacketsEstimator : public IcnRateEstimator {
+ public:
+ BatchingPacketsEstimator(double alpha_arg, int batchingParam);
+
+ void onRttUpdate(double rtt);
+
+ void onDataReceived(int packet_size) {
+ if (packet_size > this->max_packet_size_) {
+ this->max_packet_size_ = packet_size;
+ }
+ };
+
+ void onWindowIncrease(double win_current);
+
+ void onWindowDecrease(double win_current);
+
+ void onStart(){};
+
+ void onDownloadFinished(){};
+
+ private:
+ int batching_param_;
+ double avg_rtt_;
+ double avg_win_;
+ double win_change_;
+ int max_packet_size_;
+ double win_current_;
+};
+
+// Segment Estimator
+
+class ALaTcpEstimator : public IcnRateEstimator {
+ public:
+ ALaTcpEstimator();
+
+ void onDataReceived(int packet_size);
+ void onStart();
+ void onDownloadFinished();
+
+ private:
+ double totalSize_;
+};
+
+// A Rate estimator, this one is the simplest: counting batching_param_ packets
+// and then divide the sum of the size of these packets by the time taken to DL
+// them. Should be the one used
+
+class SimpleEstimator : public IcnRateEstimator {
+ public:
+ SimpleEstimator(double alpha, int batching_param);
+
+ void onRttUpdate(double rtt);
+
+ void onDataReceived(int packet_size);
+
+ void onWindowIncrease(double win_current){};
+
+ void onWindowDecrease(double win_current){};
+
+ void onStart();
+
+ void onDownloadFinished();
+
+ private:
+ int batching_param_;
+ double total_size_;
+};
+
+void *Timer(void *data);
+
+} // namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc.cc b/libtransport/src/hicn/transport/protocols/rtc.cc
new file mode 100755
index 000000000..1f42cf230
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rtc.cc
@@ -0,0 +1,813 @@
+/*
+ * 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 <math.h>
+
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/rtc.h>
+
+/*
+ * TODO
+ * 2) start/constructor/rest variable implementation
+ * 3) interest retransmission: now I always recover, we should recover only if
+ * we have enough time 4) returnContentToUser: rememeber to remove the first
+ * 32bits from the payload
+ */
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RTCTransportProtocol::RTCTransportProtocol(BaseSocket *icnet_socket)
+ : TransportProtocol(icnet_socket),
+ inflightInterests_(1 << default_values::log_2_default_buffer_size),
+ modMask_((1 << default_values::log_2_default_buffer_size) - 1) {
+ icnet_socket->getSocketOption(PORTAL, portal_);
+ reset();
+}
+
+RTCTransportProtocol::~RTCTransportProtocol() {
+ if (is_running_) {
+ stop();
+ }
+}
+
+void RTCTransportProtocol::start(
+ utils::SharableVector<uint8_t> &content_buffer) {
+
+ if(is_running_)
+ return;
+
+ is_running_ = true;
+ content_buffer_ = content_buffer.shared_from_this();
+
+ reset();
+ scheduleNextInterest();
+
+ portal_->runEventsLoop();
+ is_running_ = false;
+}
+
+void RTCTransportProtocol::stop() {
+ if(!is_running_)
+ return;
+
+ is_running_ = false;
+ portal_->stopEventsLoop();
+}
+
+void RTCTransportProtocol::resume(){
+ if(is_running_)
+ return;
+
+ is_running_ = true;
+
+ lastRoundBegin_ = std::chrono::steady_clock::now();
+ inflightInterestsCount_ = 0;
+ if(content_buffer_)
+ content_buffer_->clear();
+
+ scheduleNextInterest();
+
+ portal_->runEventsLoop();
+
+ is_running_ = false;
+}
+
+void RTCTransportProtocol::onRTCPPacket(uint8_t *packet, size_t len) {
+ //#define MASK_RTCP_VERSION 192
+ //#define MASK_TYPE_CODE 31
+ size_t read = 0;
+ uint8_t *offset = packet;
+ while (read < len) {
+ if ((((*offset) & MASK_RTCP_VERSION) >> 6) != RTCP_VERSION) {
+ TRANSPORT_LOGE("error while parsing RTCP packet, version unkwown");
+ return;
+ }
+ processRtcpHeader(offset);
+ uint16_t RTCPlen = (ntohs(*(((uint16_t *)offset) + 1)) + 1) * 4;
+ offset += RTCPlen;
+ read += RTCPlen;
+ }
+}
+
+// private
+void RTCTransportProtocol::reset() {
+ // controller var
+ lastRoundBegin_ = std::chrono::steady_clock::now();
+ currentState_ = RTC_SYNC_STATE;
+
+ // cwin var
+ currentCWin_ = INITIAL_CWIN;
+ maxCWin_ = INITIAL_CWIN_MAX;
+
+ // names/packets var
+ actualSegment_ = 0;
+ inflightInterestsCount_ = 0;
+ while (interestRetransmissions_.size() != 0) interestRetransmissions_.pop();
+ nackedByProducer_.clear();
+ nackedByProducerMaxSize_ = 512;
+ if (content_buffer_) content_buffer_->clear();
+
+ holes_.clear();
+ lastReceived_ = 0;
+
+ // stats
+ receivedBytes_ = 0;
+ sentInterest_ = 0;
+ receivedData_ = 0;
+ packetLost_ = 0;
+ avgPacketSize_ = INIT_PACKET_SIZE;
+ gotNack_ = false;
+ gotFutureNack_ = 0;
+ roundsWithoutNacks_ = 0;
+ pathTable_.clear();
+ // roundCounter_ = 0;
+ // minRTTwin_.clear();
+ // for (int i = 0; i < MIN_RTT_WIN; i++)
+ // minRTTwin_.push_back(UINT_MAX);
+ minRtt_ = UINT_MAX;
+
+ // CC var
+ estimatedBw_ = 0.0;
+ lossRate_ = 0.0;
+ queuingDelay_ = 0.0;
+ protocolState_ = RTC_NORMAL_STATE;
+
+ producerPathLabel_ = 0;
+ socket_->setSocketOption(
+ GeneralTransportOptions::INTEREST_LIFETIME,
+ (uint32_t)
+ RTC_INTEREST_LIFETIME); // XXX this should bedone by the application
+}
+
+uint32_t max(uint32_t a, uint32_t b) {
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+uint32_t min(uint32_t a, uint32_t b) {
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+void RTCTransportProtocol::checkRound() {
+ uint32_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - lastRoundBegin_)
+ .count();
+ if (duration >= ROUND_LEN) {
+ lastRoundBegin_ = std::chrono::steady_clock::now();
+ updateStats(duration); // update stats and window
+ }
+}
+
+void RTCTransportProtocol::updateDelayStats(
+ const ContentObject &content_object) {
+ uint32_t segmentNumber = content_object.getName().getSuffix();
+ uint32_t pkt = segmentNumber & modMask_;
+
+ if (inflightInterests_[pkt].transmissionTime ==
+ 0) // this is always the case if we have a retransmitted packet (timeout
+ // or RTCP)
+ return;
+
+ uint32_t pathLabel = content_object.getPathLabel();
+
+ if (pathTable_.find(pathLabel) == pathTable_.end()) {
+ // found a new path
+ std::shared_ptr<RTCDataPath> newPath = std::make_shared<RTCDataPath>();
+ pathTable_[pathLabel] = newPath;
+ }
+
+ // RTT measurements are useful both from NACKs and data packets
+ uint64_t RTT = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count() -
+ inflightInterests_[pkt].transmissionTime;
+
+ pathTable_[pathLabel]->insertRttSample(RTT);
+
+ // we collect OWD only for datapackets
+ if (content_object.getPayload().length() != NACK_HEADER_SIZE) {
+ uint64_t *senderTimeStamp = (uint64_t *)content_object.getPayload().data();
+
+ int64_t OWD = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count() -
+ *senderTimeStamp;
+
+ pathTable_[pathLabel]->insertOwdSample(OWD);
+ }
+}
+
+void RTCTransportProtocol::updateStats(uint32_t round_duration) {
+ if (receivedBytes_ != 0) {
+ double bytesPerSec = (double)(receivedBytes_ * ((double)MILLI_IN_A_SEC /
+ (double)round_duration));
+ estimatedBw_ = (estimatedBw_ * ESTIMATED_BW_ALPHA) +
+ ((1 - ESTIMATED_BW_ALPHA) * bytesPerSec);
+ }
+
+ auto it = pathTable_.find(producerPathLabel_);
+ if (it == pathTable_.end()) return;
+
+ // double maxAvgRTT = it->second->getAverageRtt();
+ // double minRTT = it->second->getMinRtt();
+ minRtt_ = it->second->getMinRtt();
+ queuingDelay_ = it->second->getQueuingDealy();
+
+ if (minRtt_ == 0) minRtt_ = 1;
+
+ for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) {
+ it->second->roundEnd();
+ }
+
+ // this is inefficient but the window is supposed to be small, so it
+ // probably makes sense to leave it like this
+ // if(minRTT == 0)
+ // minRTT = 1;
+
+ // minRTTwin_[roundCounter_ % MIN_RTT_WIN] = minRTT;
+ // minRtt_ = minRTT;
+ // for (int i = 0; i < MIN_RTT_WIN; i++)
+ // if(minRtt_ > minRTTwin_[i])
+ // minRtt_ = minRTTwin_[i];
+
+ // roundCounter_++;
+
+ // std::cout << "min RTT " << minRtt_ << " queuing " << queuingDelay_ <<
+ // std::endl;
+
+ if (sentInterest_ != 0 && currentState_ == RTC_NORMAL_STATE) {
+ double lossRate = (double)((double)packetLost_ / (double)sentInterest_);
+ lossRate_ = lossRate_ * ESTIMATED_LOSSES_ALPHA +
+ (lossRate * (1 - ESTIMATED_LOSSES_ALPHA));
+ }
+
+ if (avgPacketSize_ == 0) avgPacketSize_ = INIT_PACKET_SIZE;
+
+ uint32_t BDP =
+ ceil((estimatedBw_ * (double)((double)minRtt_ / (double)MILLI_IN_A_SEC) *
+ BANDWIDTH_SLACK_FACTOR) /
+ avgPacketSize_);
+ uint32_t BW = ceil(estimatedBw_);
+ computeMaxWindow(BW, BDP);
+
+ // bound also by interest lifitime* production rate
+ if (!gotNack_) {
+ roundsWithoutNacks_++;
+ if (currentState_ == RTC_SYNC_STATE &&
+ roundsWithoutNacks_ >= ROUNDS_IN_SYNC_BEFORE_SWITCH) {
+ currentState_ = RTC_NORMAL_STATE;
+ }
+ } else {
+ roundsWithoutNacks_ = 0;
+ }
+
+ updateCCState();
+ updateWindow();
+
+ // in any case we reset all the counters
+
+ gotNack_ = false;
+ gotFutureNack_ = 0;
+ receivedBytes_ = 0;
+ sentInterest_ = 0;
+ receivedData_ = 0;
+ packetLost_ = 0;
+}
+
+void RTCTransportProtocol::updateCCState() {
+ // TODO
+}
+
+void RTCTransportProtocol::computeMaxWindow(uint32_t productionRate,
+ uint32_t BDPWin) {
+ if (productionRate ==
+ 0) // we have no info about the producer, keep the previous maxCWin
+ return;
+
+ uint32_t interestLifetime = default_values::interest_lifetime;
+ socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+ interestLifetime);
+ uint32_t maxWaintingInterest = ceil(
+ (productionRate / avgPacketSize_) *
+ (double)((double)(interestLifetime * INTEREST_LIFETIME_REDUCTION_FACTOR) /
+ (double)MILLI_IN_A_SEC));
+
+ if (currentState_ == RTC_SYNC_STATE) {
+ // in this case we do not limit the window with the BDP, beacuse most likly
+ // it is wrong
+ maxCWin_ = maxWaintingInterest;
+ return;
+ }
+
+ // currentState = RTC_NORMAL_STATE
+ if (BDPWin != 0) {
+ maxCWin_ = ceil((double)BDPWin + ((double)BDPWin / 10.0)); // BDP + 10%
+ } else {
+ maxCWin_ = min(maxWaintingInterest, maxCWin_);
+ }
+}
+
+void RTCTransportProtocol::updateWindow() {
+ if (currentState_ == RTC_SYNC_STATE) return;
+
+ if (currentCWin_ < maxCWin_ * 0.7) {
+ currentCWin_ = min(maxCWin_, currentCWin_ * WIN_INCREASE_FACTOR);
+ } else if (currentCWin_ > maxCWin_) {
+ currentCWin_ = max(currentCWin_ * WIN_DECREASE_FACTOR, MIN_CWIN);
+ }
+}
+
+void RTCTransportProtocol::decreaseWindow() {
+ // this is used only in SYNC mode
+ if (currentState_ == RTC_NORMAL_STATE) return;
+
+ if (gotFutureNack_ == 1)
+ currentCWin_ =
+ min((currentCWin_ - 1), ceil((double)maxCWin_ * 0.66)); // 2/3
+ else
+ currentCWin_--;
+
+ currentCWin_ = max(currentCWin_, MIN_CWIN);
+}
+
+void RTCTransportProtocol::increaseWindow() {
+ // this is used only in SYNC mode
+ if (currentState_ == RTC_NORMAL_STATE) return;
+
+ // we need to be carefull to do not increase the window to much
+ if (currentCWin_ < ((double)maxCWin_ * 0.5)) {
+ currentCWin_ = currentCWin_ + 1; // exponential
+ } else {
+ currentCWin_ = min(
+ maxCWin_, ceil(currentCWin_ + (1.0 / (double)currentCWin_))); // linear
+ }
+}
+
+void RTCTransportProtocol::sendInterest() {
+ Name interest_name;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
+ interest_name);
+ bool isRTX = false;
+ // uint32_t sentInt = 0;
+
+ if (interestRetransmissions_.size() > 0) {
+ // handle retransmission
+ // here we have two possibile retransmissions: retransmissions due to
+ // timeouts and retransmissions due to RTCP NACKs. we will send the interest
+ // anyway, even if it is pending (this is possible only in the second case)
+ uint32_t rtxSeg = interestRetransmissions_.front();
+ interestRetransmissions_.pop();
+
+ std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+ holes_.find(rtxSeg);
+ if (res != holes_.end()) {
+ // this packet is already managed by as an hole
+ // we don't need to send it again
+ return;
+ }
+
+ // a packet recovery means that there was a loss
+ packetLost_++;
+
+ uint32_t pkt = rtxSeg & modMask_;
+ interest_name.setSuffix(rtxSeg);
+
+ // if the interest is not pending anymore we encrease the retrasnmission
+ // counter in order to avoid to handle a recovered packt as a normal one
+ if (!portal_->interestIsPending(interest_name)) {
+ inflightInterests_[pkt].retransmissions++;
+ }
+
+ inflightInterests_[pkt].transmissionTime = 0;
+ isRTX = true;
+ } else {
+ // in this case we send the packet only if it is not pending yet
+ interest_name.setSuffix(actualSegment_);
+ if (portal_->interestIsPending(interest_name)) {
+ actualSegment_++;
+ return;
+ }
+
+ // sentInt = actualSegment_;
+ uint32_t pkt = actualSegment_ & modMask_;
+ inflightInterests_[pkt].transmissionTime =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ inflightInterests_[pkt].retransmissions = 0;
+ actualSegment_++;
+ }
+
+ auto interest = getInterest();
+ interest->setName(interest_name);
+
+ uint32_t interestLifetime = default_values::interest_lifetime;
+ socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+ interestLifetime);
+ interest->setLifetime(uint32_t(interestLifetime));
+
+ ConsumerInterestCallback on_interest_output = VOID_HANDLER;
+
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
+ on_interest_output);
+
+ if (on_interest_output != VOID_HANDLER) {
+ on_interest_output(*dynamic_cast<ConsumerSocket *>(socket_), *interest);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ using namespace std::placeholders;
+ portal_->sendInterest(std::move(interest));
+
+ sentInterest_++;
+
+ if (!isRTX) {
+ inflightInterestsCount_++;
+ }
+}
+
+void RTCTransportProtocol::scheduleNextInterest() {
+ checkRound();
+ if(!is_running_)
+ return;
+
+ uint32_t MAX_RECOVER =
+ 40; // if the packet is more than MAX_RECOVER seq in the past we drop it
+ uint64_t TIME_BEFORE_RECOVERY = 10; // this should be proporsional to the RTT
+
+ // holes are important only in NORMAL state
+ if (currentState_ == RTC_NORMAL_STATE) {
+ for (std::unordered_map<uint32_t, uint64_t>::iterator it = holes_.begin();
+ it != holes_.end();) {
+ if (it->first < lastReceived_ - MAX_RECOVER) {
+ // the packet is to hold, remove it
+ it = holes_.erase(it);
+ } else {
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ uint64_t sinceLastTry = now - it->second;
+
+ if (sinceLastTry > TIME_BEFORE_RECOVERY || it->second == 0) {
+ // a recovery means a packet lost
+ packetLost_++;
+ // update last sent time
+ it->second = now;
+
+ Name interest_name;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
+ interest_name);
+
+ uint32_t pkt = it->first & modMask_;
+ interest_name.setSuffix(it->first);
+
+ if (!portal_->interestIsPending(interest_name)) {
+ inflightInterests_[pkt].retransmissions++;
+ }
+
+ inflightInterests_[pkt].transmissionTime = 0;
+ // XXX
+ // code refactoring:
+ // from here on this is a copy and paste of the code inside
+ // sendInterest this should go inside an other method
+ auto interest = getInterest();
+ uint32_t interestLifetime = default_values::interest_lifetime;
+ socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+ interestLifetime);
+ interest->setLifetime(uint32_t(interestLifetime));
+
+ ConsumerInterestCallback on_interest_output = VOID_HANDLER;
+
+ socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
+ on_interest_output);
+ if (on_interest_output != VOID_HANDLER)
+ on_interest_output(*dynamic_cast<ConsumerSocket *>(socket_),
+ *interest);
+
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) return;
+
+ using namespace std::placeholders;
+ portal_->sendInterest(std::move(interest));
+
+ sentInterest_++;
+ }
+ ++it;
+ }
+ // as usual check the round at each packet
+ checkRound();
+ }
+ }
+
+ while (interestRetransmissions_.size() > 0) {
+ sendInterest();
+ checkRound();
+ }
+
+ while (inflightInterestsCount_ < currentCWin_) {
+ sendInterest();
+ checkRound();
+ }
+}
+
+void RTCTransportProtocol::scheduleAppNackRtx(std::vector<uint32_t> &nacks) {
+ for (uint32_t i = 0; i < nacks.size(); i++) {
+ if (nackedByProducer_.find(nacks[i]) != nackedByProducer_.end()) {
+ continue;
+ }
+ // packetLost_++;
+ // XXX here I need to avoid the retrasmission for packet that were nacked by
+ // the network
+ interestRetransmissions_.push(nacks[i]);
+ }
+
+ scheduleNextInterest();
+}
+void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+ // packetLost_++;
+
+ uint32_t segmentNumber = interest->getName().getSuffix();
+ uint32_t pkt = segmentNumber & modMask_;
+
+ if (inflightInterests_[pkt].retransmissions == 0) {
+ inflightInterestsCount_--;
+ }
+
+ if (inflightInterests_[pkt].retransmissions < MAX_RTX) {
+ interestRetransmissions_.push(segmentNumber);
+ }
+
+ scheduleNextInterest();
+}
+
+void RTCTransportProtocol::onNack(const ContentObject &content_object) {
+ uint32_t *payload = (uint32_t *)content_object.getPayload().data();
+ uint32_t productionSeg = *payload;
+ uint32_t productionRate = *(++payload);
+ uint32_t nackSegment = content_object.getName().getSuffix();
+
+ // we synch the estimated production rate with the actual one
+ estimatedBw_ = (double)productionRate;
+
+ // if(inflightInterests_[segmentNumber %
+ // default_values::default_buffer_size].retransmissions != 0){ ignore nacks for
+ // retransmissions
+ // return;
+ //}
+
+ gotNack_ = true;
+
+ if (productionSeg > nackSegment) {
+ // we are asking for stuff produced in the past
+ actualSegment_ = max(productionSeg + 1, actualSegment_);
+ if (currentState_ == RTC_NORMAL_STATE) {
+ currentState_ = RTC_SYNC_STATE;
+ // if we switch in SYNC mode we do not care about holes
+ // se we reset the data structure. going back to NORMAL
+ // mode will anable again the holes_ check.
+ holes_.clear();
+ lastReceived_ = 0;
+ }
+
+ computeMaxWindow(productionRate, 0);
+ increaseWindow();
+
+ if (nackedByProducer_.size() >= nackedByProducerMaxSize_)
+ nackedByProducer_.erase(nackedByProducer_.begin());
+ nackedByProducer_.insert(nackSegment);
+
+ } else if (productionSeg < nackSegment) {
+ gotFutureNack_++;
+ // we are asking stuff in the future
+ // example
+ // 10 12 13 14 15 16 17
+ // ^ ^ ^
+ // in prod nack actual
+ // in this example we sent up to segment 17 and we get a nack for segment 15
+ // this means that we will get nack also for 16 17
+ // and valid data for 13 14
+ // so the next segment to ask is 15, because 13 and 14 will can back anyway
+ // we go back only in the case that the actual segment is really bigger than
+ // nack segment, other we do nothing
+
+ actualSegment_ = min(actualSegment_, nackSegment);
+
+ computeMaxWindow(productionRate, 0);
+ decreaseWindow();
+
+ if (currentState_ == RTC_SYNC_STATE) {
+ currentState_ = RTC_NORMAL_STATE;
+ }
+ } // equal should not happen
+}
+
+void RTCTransportProtocol::onContentObject(
+ Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+ uint32_t payload_size = content_object->getPayload().length();
+ uint32_t segmentNumber = content_object->getName().getSuffix();
+ uint32_t pkt = segmentNumber & modMask_;
+
+ // try to recover holes
+ // we can recover haoles with valid data, nacks or retransmitted packets
+ bool recoveredHole = false;
+ std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+ holes_.find(segmentNumber);
+ if (res != holes_.end()) {
+ holes_.erase(res);
+ recoveredHole = true;
+ }
+
+ if (payload_size == NACK_HEADER_SIZE) {
+ // Nacks always come form the producer, so we set the producerePathLabel_;
+ producerPathLabel_ = content_object->getPathLabel();
+ if (inflightInterests_[pkt].retransmissions == 0) {
+ inflightInterestsCount_--;
+ onNack(*content_object);
+ updateDelayStats(*content_object);
+ }
+
+ } else {
+ receivedData_++;
+
+ avgPacketSize_ =
+ (ESTIMATED_PACKET_SIZE * avgPacketSize_) +
+ ((1 - ESTIMATED_PACKET_SIZE) * content_object->getPayload().length());
+
+ if (inflightInterests_[pkt].retransmissions == 0) {
+ inflightInterestsCount_--;
+ // we count only non retransmitted data in order to take into accunt only
+ // the transmition rate of the producer
+ receivedBytes_ +=
+ content_object->headerSize() + content_object->payloadSize();
+ updateDelayStats(*content_object);
+
+ // handle holes
+ // the packet sequence make sense only in case of valid data (no nacks, no
+ // rtx) in RTC_NORMAL_STATE we should get all the packets in order, so if
+ // segmentNumber != lastReceived + 1 something happened
+ // if recoveredHole == true this is a packet recovered so we should do
+ // nothing
+ if (currentState_ == RTC_NORMAL_STATE && recoveredHole == false) {
+ if ((segmentNumber != lastReceived_ + 1) &&
+ segmentNumber > lastReceived_) {
+ // we have holes in the sequence
+ for (uint32_t seq = lastReceived_ + 1; seq < segmentNumber; seq++) {
+ // the hole exists we do not insert it again
+ std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+ holes_.find(seq);
+ if (res == holes_.end())
+ holes_.insert(std::make_pair(seq, 0)); // 0 means never sent
+ }
+ }
+ }
+
+ // this if should be always true
+ if (segmentNumber > lastReceived_) {
+ lastReceived_ = segmentNumber;
+ }
+ }
+
+ returnContentToUser(*content_object);
+ increaseWindow();
+ }
+
+ scheduleNextInterest();
+}
+
+void RTCTransportProtocol::returnContentToUser(
+ const ContentObject &content_object) {
+ // return content to the user
+ Array a = content_object.getPayload();
+
+ uint8_t *start = ((uint8_t *)a.data()) + TIMESTAMP_SIZE;
+ unsigned size = a.length() - TIMESTAMP_SIZE;
+
+ // set offset between hICN and RTP packets
+ uint16_t rtp_seq = ntohs(*(((uint16_t *)start) + 1));
+ RTPhICN_offset_ = content_object.getName().getSuffix() - rtp_seq;
+
+ content_buffer_->insert(content_buffer_->end(), start, start + size);
+
+ ConsumerContentCallback on_payload = VOID_HANDLER;
+ socket_->getSocketOption(CONTENT_RETRIEVED, on_payload);
+ if (on_payload != VOID_HANDLER) {
+ on_payload(*dynamic_cast<ConsumerSocket *>(socket_), size,
+ std::make_error_code(std::errc(0)));
+ }
+}
+
+uint32_t RTCTransportProtocol::hICN2RTP(uint32_t hicn_seq) {
+ return RTPhICN_offset_ - hicn_seq;
+}
+
+uint32_t RTCTransportProtocol::RTP2hICN(uint32_t rtp_seq) {
+ return RTPhICN_offset_ + rtp_seq;
+}
+
+void RTCTransportProtocol::processRtcpHeader(uint8_t *offset) {
+ uint8_t pkt_type = (*(offset + 1));
+ switch (pkt_type) {
+ case RTCP_RR: // Receiver report
+ TRANSPORT_LOGI("got RR packet\n");
+ break;
+ case RTCP_SR: // Sender report
+ TRANSPORT_LOGI("got SR packet\n");
+ break;
+ case RTCP_SDES: // Description
+ processSDES(offset);
+ break;
+ case RTCP_RTPFB: // Transport layer FB message
+ processGenericNack(offset);
+ break;
+ case RTCP_PSFB:
+ processPli(offset);
+ break;
+ default:
+ errorParsingRtcpHeader(offset);
+ }
+}
+
+void RTCTransportProtocol::errorParsingRtcpHeader(uint8_t *offset) {
+ uint8_t pt = (*(offset + 1));
+ uint8_t code = ((*offset) & MASK_TYPE_CODE);
+ TRANSPORT_LOGE("Received unknwnon RTCP packet. Payload type = %u, code = %u",
+ pt, code);
+}
+
+void RTCTransportProtocol::processSDES(uint8_t *offset) {
+ uint8_t code = ((*offset) & MASK_TYPE_CODE);
+ switch (code) {
+ case RTCP_SDES_CNAME:
+ TRANSPORT_LOGI("got SDES packet: CNAME\n");
+ break;
+ default:
+ errorParsingRtcpHeader(offset);
+ }
+}
+
+void RTCTransportProtocol::processPli(uint8_t *offset) {
+ if (((*offset) & MASK_TYPE_CODE) != RTCP_PSFB_PLI) {
+ errorParsingRtcpHeader(offset);
+ return;
+ }
+
+ TRANSPORT_LOGI("got PLI packet\n");
+}
+
+void RTCTransportProtocol::processGenericNack(uint8_t *offset) {
+ if (((*offset) & MASK_TYPE_CODE) != RTCP_RTPFB_GENERIC_NACK) {
+ errorParsingRtcpHeader(offset);
+ return;
+ }
+
+ std::vector<uint32_t> nacks;
+
+ uint16_t header_lines =
+ ntohs(*(((uint16_t *)offset) + 1)) -
+ 2; // 2 is the number of header 32-bits words - 1 (RFC 4885)
+ uint8_t *payload = offset + RTPC_NACK_HEADER; // 12 bytes
+ for (uint16_t l = header_lines; l > 0; l--) {
+ nacks.push_back(RTP2hICN(ntohs(*((uint16_t *)payload))));
+
+ uint16_t BLP = ntohs(*(((uint16_t *)payload) + 1));
+
+ for (int bit = 0; bit < 15; bit++) { // 16 bits word to scan
+ if ((BLP >> bit) & 1) {
+ nacks.push_back(RTP2hICN((ntohs(*((uint16_t *)payload)) + bit + 1) %
+ MAX_RTCP_SEQ_NUMBER));
+ }
+ }
+
+ payload += 4; // go to the next line
+ }
+
+ portal_->getIoService().post(std::bind(
+ &RTCTransportProtocol::scheduleAppNackRtx, this, std::move(nacks)));
+}
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc.h b/libtransport/src/hicn/transport/protocols/rtc.h
new file mode 100755
index 000000000..249af6b99
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rtc.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiTC_SYNC_STATE
+ * 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 <queue>
+#include <set>
+#include <unordered_map>
+
+#include <hicn/transport/protocols/protocol.h>
+#include <hicn/transport/protocols/rtc_data_path.h>
+
+// algorithm state
+#define RTC_SYNC_STATE 0
+#define RTC_NORMAL_STATE 1
+#define ROUNDS_IN_SYNC_BEFORE_SWITCH 3
+
+// packet constants
+#define INIT_PACKET_SIZE 1300 // bytes
+#define HICN_PACKET_HEADER_SIZE 60 // bytes ipv6+tcp
+#define NACK_HEADER_SIZE 8 // bytes
+#define TIMESTAMP_SIZE 8 // bytes
+#define RTC_INTEREST_LIFETIME 1000 // ms
+
+// controller constant
+#define ROUND_LEN \
+ 200 // ms interval of time on which we take decisions / measurements
+#define MAX_RTX 128
+#define MIN_RTT_WIN 30 // rounds
+
+// cwin
+#define INITIAL_CWIN 1 // packets
+#define INITIAL_CWIN_MAX 100000 // packets
+#define MIN_CWIN 5 // packets
+
+// statistics constants
+#define BANDWIDTH_SLACK_FACTOR 1.5
+#define ESTIMATED_BW_ALPHA 0.7
+#define ESTIMATED_PACKET_SIZE 0.7
+#define ESTIMATED_LOSSES_ALPHA 0.8
+#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8
+
+//#define MAX_LOSS_RATE 0.05
+//#define MAX_QUEUING_DELAY 200 //ms
+
+// cwin
+#define INITIAL_CWIN 1
+#define MIN_CWIN 5
+#define WIN_DECREASE_FACTOR 0.8
+#define WIN_INCREASE_FACTOR 1.1
+
+// protocol state
+//#define RTC_CONGESTED_STATE 10
+//#define RTC_LOSSY_STATE 20
+//#define RTC_DELAY_STATE 30
+//#define RTC_NORMAL_STATE 40
+
+// other constants
+#define NANO_IN_A_SEC 1000000000
+#define MICRO_IN_A_SEC 1000000
+#define MILLI_IN_A_SEC 1000
+
+// RTCP
+#define MASK_RTCP_VERSION 192
+#define MASK_TYPE_CODE \
+ 31 // this is RC in the RR/SR packet or FMT int the early feedback packets
+#define RTPC_NACK_HEADER 12 // bytes
+#define MAX_RTCP_SEQ_NUMBER 0xffff
+#define RTCP_VERSION 2
+// RTCP TYPES
+#define RTCP_SR 200
+#define RTCP_RR 201
+#define RTCP_SDES 202
+#define RTCP_RTPFB 205
+#define RTCP_PSFB 206
+// RTCP RC/FMT
+#define RTCP_SDES_CNAME 1
+#define RTCP_RTPFB_GENERIC_NACK 1
+#define RTCP_PSFB_PLI 1
+
+namespace transport {
+
+namespace protocol {
+
+struct sentInterest {
+ uint64_t transmissionTime;
+ uint8_t retransmissions;
+};
+
+class RTCTransportProtocol : public TransportProtocol {
+ public:
+ RTCTransportProtocol(interface::BaseSocket *icnet_socket);
+
+ ~RTCTransportProtocol();
+
+ void start(utils::SharableVector<uint8_t> &content_buffer);
+
+ void stop();
+
+ void resume();
+
+ void onRTCPPacket(uint8_t *packet, size_t len);
+
+ private:
+ // algo functions
+ void reset();
+ void checkRound();
+
+ // CC functions
+ void updateDelayStats(const ContentObject &content_object);
+ void updateStats(uint32_t round_duration);
+ void updateCCState();
+ void computeMaxWindow(uint32_t productionRate, uint32_t BDPWin);
+ void updateWindow();
+ void decreaseWindow();
+ void increaseWindow();
+ void resetPreviousWindow();
+
+ // packet functions
+ void sendInterest();
+ void scheduleNextInterest();
+ void scheduleAppNackRtx(std::vector<uint32_t> &nacks);
+ void onTimeout(Interest::Ptr &&interest);
+ void onNack(const ContentObject &content_object);
+ void onContentObject(Interest::Ptr &&interest,
+ ContentObject::Ptr &&content_object);
+ void returnContentToUser(const ContentObject &content_object);
+
+ // RTCP functions
+ uint32_t hICN2RTP(uint32_t hicn_seq);
+ uint32_t RTP2hICN(uint32_t rtp_seq);
+ void processRtcpHeader(uint8_t *offset);
+ void errorParsingRtcpHeader(uint8_t *offset);
+ void processSDES(uint8_t *offset);
+ void processGenericNack(uint8_t *offset);
+ void processPli(uint8_t *offset);
+
+ // controller var
+ std::chrono::steady_clock::time_point lastRoundBegin_;
+ // bool allPacketsInSync_;
+ // unsigned numberOfRoundsInSync_;
+ // unsigned numberOfCatchUpRounds_;
+ // bool catchUpPhase_;
+ unsigned currentState_;
+
+ // uint32_t inProduction_;
+
+ // cwin var
+ uint32_t currentCWin_;
+ uint32_t maxCWin_;
+ // uint32_t previousCWin_;
+
+ // names/packets var
+ uint32_t actualSegment_;
+ int32_t RTPhICN_offset_;
+ uint32_t inflightInterestsCount_;
+ std::queue<uint32_t> interestRetransmissions_;
+ std::vector<sentInterest> inflightInterests_;
+ uint32_t nackedByProducerMaxSize_;
+ std::set<uint32_t>
+ nackedByProducer_; // this is used to avoid retransmissions from the
+ // application for pakets for which we already got a
+ // past NACK by the producer these packet are too old,
+ // they will never be retrived
+ std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+ uint32_t modMask_;
+
+ // stats
+ uint32_t receivedBytes_;
+ uint32_t sentInterest_;
+ uint32_t receivedData_;
+ uint32_t packetLost_;
+ double avgPacketSize_;
+ bool gotNack_;
+ uint32_t gotFutureNack_;
+ uint32_t roundsWithoutNacks_;
+ uint32_t producerPathLabel_; // XXX we pick only one path lable for the
+ // producer for now, assuming the usage of a
+ // single path this should be extended to a
+ // vector
+ std::unordered_map<uint32_t, std::shared_ptr<RTCDataPath>> pathTable_;
+ uint32_t roundCounter_;
+ // std::vector<uint64_t> minRTTwin_;
+ uint64_t minRtt_;
+
+ std::unordered_map<uint32_t, uint64_t> holes_;
+ uint32_t lastReceived_;
+
+ // CC var
+ double estimatedBw_;
+ double lossRate_;
+ double queuingDelay_;
+ unsigned protocolState_;
+};
+
+} // namespace protocol
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.cc b/libtransport/src/hicn/transport/protocols/rtc_data_path.cc
new file mode 100755
index 000000000..6c9605fb2
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rtc_data_path.cc
@@ -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.
+ */
+
+#include <hicn/transport/protocols/rtc_data_path.h>
+
+namespace transport {
+
+namespace protocol {
+
+RTCDataPath::RTCDataPath()
+ : min_rtt(UINT_MAX),
+ prev_min_rtt(UINT_MAX),
+ min_owd(INT_MAX), // this is computed like in LEDBAT, so it is not the
+ // real OWD, but the measured one, that depends on the
+ // clock of sender and receiver. the only meaningful
+ // value is is the queueing delay. for this reason we
+ // keep both RTT (for the windowd calculation) and OWD
+ // (for congestion/quality control)
+ prev_min_owd(INT_MAX),
+ avg_owd(0.0),
+ queuing_delay(0.0),
+ RTThistory_(HISTORY_LEN),
+ OWDhistory_(HISTORY_LEN){};
+
+void RTCDataPath::insertRttSample(uint64_t rtt) {
+ // for the rtt we only keep track of the min one
+ if (rtt < min_rtt) min_rtt = rtt;
+}
+
+void RTCDataPath::insertOwdSample(int64_t owd) {
+ // for owd we use both min and avg
+ if (owd < min_owd) min_owd = owd;
+
+ avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC);
+}
+
+void RTCDataPath::roundEnd() {
+ // compute queuing delay
+ queuing_delay = avg_owd - getMinOwd();
+
+ // reset min_rtt and add it to the history
+ if (min_rtt != UINT_MAX) {
+ prev_min_rtt = min_rtt;
+ } else {
+ // this may happen if we do not receive any packet
+ // from this path in the last round. in this case
+ // we use the measure from the previuos round
+ min_rtt = prev_min_rtt;
+ }
+
+ RTThistory_.pushBack(min_rtt);
+ min_rtt = UINT_MAX;
+
+ // do the same for min owd
+ if (min_owd != INT_MAX) {
+ prev_min_owd = min_owd;
+ } else {
+ min_owd = prev_min_owd;
+ }
+
+ OWDhistory_.pushBack(min_owd);
+ min_owd = INT_MAX;
+}
+
+double RTCDataPath::getQueuingDealy() { return queuing_delay; }
+
+uint64_t RTCDataPath::getMinRtt() { return RTThistory_.begin(); }
+
+int64_t RTCDataPath::getMinOwd() { return OWDhistory_.begin(); }
+
+} // end namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.h b/libtransport/src/hicn/transport/protocols/rtc_data_path.h
new file mode 100755
index 000000000..ace16ff12
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/rtc_data_path.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdint.h>
+#include <hicn/transport/utils/min_filter.h>
+#include <climits>
+
+#define ALPHA_RTC 0.125
+#define HISTORY_LEN 30
+
+namespace transport {
+
+namespace protocol {
+
+class RTCDataPath {
+ public:
+ RTCDataPath();
+
+ public:
+ void insertRttSample(uint64_t rtt);
+ void insertOwdSample(int64_t owd);
+
+ uint64_t getMinRtt();
+
+ double getQueuingDealy();
+
+ void roundEnd();
+
+ private:
+ int64_t getMinOwd();
+
+ uint64_t min_rtt;
+ uint64_t prev_min_rtt;
+
+ int64_t min_owd;
+ int64_t prev_min_owd;
+
+ double avg_owd;
+
+ double queuing_delay;
+
+ utils::MinFilter<uint64_t> RTThistory_;
+ utils::MinFilter<int64_t> OWDhistory_;
+};
+
+} // namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt
new file mode 100755
index 000000000..6f9fdb9aa
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/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_transport_producer)
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach() \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc b/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc
new file mode 100755
index 000000000..204f2cbe2
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc
@@ -0,0 +1,80 @@
+/*
+ * 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 "../socket_producer.h"
+#include "literals.h"
+
+#include <test.h>
+#include <random>
+
+namespace transport {
+
+namespace protocol {
+
+namespace {
+// The fixture for testing class Foo.
+class ProducerTest : public ::testing::Test {
+ protected:
+ ProducerTest() : name_("b001::123|321"), producer_(io_service_) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~ProducerTest() {
+ // 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_;
+ asio::io_service io_service_;
+ ProducerSocket producer_;
+};
+
+} // namespace
+
+// Tests that the Foo::Bar() method does Abc.
+TEST_F(ProducerTest, ProduceContent) {
+ std::string content(250000, '?');
+
+ producer_.registerPrefix(Prefix("b001::/64"));
+ producer_.produce(name_, reinterpret_cast<const uint8_t *>(content.data()),
+ content.size(), true);
+ producer_.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+ 500000000_U32);
+ producer_.attach();
+ producer_.serveForever();
+}
+
+} // namespace protocol
+
+} // 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/protocols/vegas.cc b/libtransport/src/hicn/transport/protocols/vegas.cc
new file mode 100755
index 000000000..b6d79bfcc
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/vegas.cc
@@ -0,0 +1,630 @@
+/*
+ * 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/errors/not_implemented_exception.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/utils/literals.h>
+
+#include <cmath>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+VegasTransportProtocol::VegasTransportProtocol(BaseSocket *icnet_socket)
+ : TransportProtocol(icnet_socket),
+ is_final_block_number_discovered_(false),
+ final_block_number_(std::numeric_limits<uint32_t>::max()),
+ last_reassembled_segment_(0),
+ content_buffer_size_(0),
+ current_window_size_(default_values::min_window_size),
+ interests_in_flight_(0),
+ next_suffix_(0),
+ interest_retransmissions_(1 << default_values::log_2_default_buffer_size),
+ interest_timepoints_(1 << default_values::log_2_default_buffer_size),
+ retx_count_(0),
+ receive_buffer_(1 << default_values::log_2_default_buffer_size),
+ unverified_segments_(1 << default_values::log_2_default_buffer_size),
+ verified_manifests_(1 << default_values::log_2_default_buffer_size),
+ mask_((1 << default_values::log_2_default_buffer_size) - 1),
+ incremental_suffix_index_(0),
+ suffix_queue_completed_(false),
+ download_with_manifest_(false),
+ next_manifest_interval_(0_U16),
+ interest_tx_(0),
+ interest_count_(0),
+ byte_count_(0),
+ average_rtt_(0.0) {
+ portal_ = socket_->portal_;
+ incremental_suffix_index_++;
+}
+
+VegasTransportProtocol::~VegasTransportProtocol() { stop(); }
+
+void VegasTransportProtocol::reset() {
+ portal_->setConsumerCallback(this);
+
+ is_final_block_number_discovered_ = false;
+ interest_pool_index_ = 0;
+ final_block_number_ = std::numeric_limits<uint32_t>::max();
+ next_suffix_ = 0;
+ interests_in_flight_ = 0;
+ last_reassembled_segment_ = 0;
+ content_buffer_size_ = 0;
+ content_buffer_->clear();
+ interest_retransmissions_.clear();
+ interest_retransmissions_.resize(
+ 1 << default_values::log_2_default_buffer_size, 0);
+ interest_timepoints_.clear();
+ interest_timepoints_.resize(1 << default_values::log_2_default_buffer_size,
+ std::chrono::steady_clock::time_point());
+ receive_buffer_.clear();
+ unverified_segments_.clear();
+ verified_manifests_.clear();
+ next_manifest_interval_ = 0;
+ next_manifest_ = 0;
+ download_with_manifest_ = false;
+ incremental_suffix_index_ = 0;
+
+ interest_tx_ = 0;
+ interest_count_ = 0;
+ byte_count_ = 0;
+ average_rtt_ = 0;
+
+ // asio::io_service &io_service = portal_->getIoService();
+
+ // if (io_service.stopped()) {
+ // io_service.reset();
+ // }
+}
+
+void VegasTransportProtocol::start(
+ utils::SharableVector<uint8_t> &content_buffer) {
+
+ if(is_running_)
+ return;
+
+ socket_->t0_ = std::chrono::steady_clock::now();
+
+ is_running_ = true;
+ content_buffer_ = content_buffer.shared_from_this();
+
+ reset();
+
+ sendInterest(next_suffix_++);
+ portal_->runEventsLoop();
+ removeAllPendingInterests();
+ is_running_ = false;
+
+}
+
+void VegasTransportProtocol::resume(){
+ if(is_running_)
+ return;
+
+ is_running_ = true;
+ sendInterest(next_suffix_++);
+ portal_->runEventsLoop();
+ removeAllPendingInterests();
+ is_running_ = false;
+}
+
+void VegasTransportProtocol::sendInterest(std::uint64_t next_suffix) {
+ auto interest = getInterest();
+ socket_->network_name_.setSuffix(next_suffix);
+ interest->setName(socket_->network_name_);
+
+ interest->setLifetime(uint32_t(socket_->interest_lifetime_));
+
+ if (socket_->on_interest_output_ != VOID_HANDLER) {
+ socket_->on_interest_output_(*socket_, *interest);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ interests_in_flight_++;
+ interest_retransmissions_[next_suffix & mask_] = 0;
+ interest_timepoints_[next_suffix & mask_] = std::chrono::steady_clock::now();
+
+ using namespace std::placeholders;
+ portal_->sendInterest(std::move(interest));
+}
+
+void VegasTransportProtocol::stop() {
+ is_running_ = false;
+ portal_->stopEventsLoop();
+}
+
+void VegasTransportProtocol::onContentSegment(
+ Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+ uint32_t incremental_suffix = content_object->getName().getSuffix();
+ bool virtual_download = socket_->virtual_download_;
+
+ if (verifyContentObject(*content_object)) {
+ byte_count_ += content_object->getPayload().length();
+
+ if (TRANSPORT_EXPECT_FALSE(content_object->testRst())) {
+ is_final_block_number_discovered_ = true;
+ final_block_number_ = incremental_suffix;
+ }
+
+ if (!virtual_download) {
+ receive_buffer_.emplace(
+ std::make_pair(incremental_suffix, std::move(content_object)));
+ reassemble();
+ } else if (TRANSPORT_EXPECT_FALSE(is_final_block_number_discovered_ &&
+ incremental_suffix ==
+ final_block_number_)) {
+ returnContentToUser();
+ }
+ } else {
+ unverified_segments_.emplace(
+ std::make_pair(incremental_suffix, std::move(content_object)));
+ }
+}
+
+void VegasTransportProtocol::afterContentReception(
+ const Interest &interest, const ContentObject &content_object) {
+ increaseWindow();
+}
+
+void VegasTransportProtocol::afterDataUnsatisfied(uint64_t segment) {
+ decreaseWindow();
+}
+
+void VegasTransportProtocol::scheduleNextInterests() {
+ if (is_running_) {
+ uint32_t next_suffix;
+ while (interests_in_flight_ < current_window_size_) {
+ if (download_with_manifest_) {
+ if (suffix_queue_.size() * 2 < current_window_size_ &&
+ next_manifest_ < final_block_number_ && next_manifest_interval_) {
+ next_manifest_ += next_manifest_interval_;
+ sendInterest(next_manifest_);
+ continue;
+ }
+
+ if (suffix_queue_.pop(next_suffix)) {
+ // next_suffix = suffix_queue_.front();
+ sendInterest(next_suffix);
+ // suffix_queue_.pop_front();
+ } else {
+ if (!suffix_queue_completed_) {
+ TRANSPORT_LOGE("Empty queue!!!!!!");
+ }
+ break;
+ }
+ } else {
+ if (is_final_block_number_discovered_) {
+ if (next_suffix_ > final_block_number_) {
+ return;
+ }
+ }
+
+ sendInterest(next_suffix_++);
+ }
+ }
+ }
+}
+
+void VegasTransportProtocol::decreaseWindow() {
+ if (current_window_size_ > socket_->min_window_size_) {
+ current_window_size_ = std::ceil(current_window_size_ / 2);
+ socket_->current_window_size_ = current_window_size_;
+ }
+}
+
+void VegasTransportProtocol::increaseWindow() {
+ if (current_window_size_ < socket_->max_window_size_) {
+ current_window_size_++;
+ socket_->max_window_size_ = current_window_size_;
+ }
+};
+
+void VegasTransportProtocol::changeInterestLifetime(uint64_t segment) {
+ std::chrono::steady_clock::duration duration =
+ std::chrono::steady_clock::now() - interest_timepoints_[segment];
+ rtt_estimator_.addMeasurement(
+ std::chrono::duration_cast<std::chrono::microseconds>(duration));
+
+ RtoEstimator::Duration rto = rtt_estimator_.computeRto();
+ std::chrono::milliseconds lifetime =
+ std::chrono::duration_cast<std::chrono::milliseconds>(rto);
+
+ socket_->interest_lifetime_ = lifetime.count();
+}
+
+void VegasTransportProtocol::returnContentToUser() {
+ if (socket_->on_payload_retrieved_ != VOID_HANDLER) {
+ socket_->on_payload_retrieved_(*socket_, byte_count_,
+ std::make_error_code(std::errc(0)));
+ }
+
+ stop();
+}
+
+void VegasTransportProtocol::onManifest(
+ std::unique_ptr<ContentObjectManifest> &&manifest) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ download_with_manifest_ = true;
+
+ uint32_t segment = manifest->getName().getSuffix();
+
+ if (verifyManifest(*manifest)) {
+ manifest->decode();
+
+ if (TRANSPORT_EXPECT_TRUE(manifest->getVersion() ==
+ core::ManifestVersion::VERSION_1)) {
+ switch (manifest->getManifestType()) {
+ case core::ManifestType::INLINE_MANIFEST: {
+ auto _it = manifest->getSuffixList().begin();
+ auto _end = --manifest->getSuffixList().end();
+
+ if (TRANSPORT_EXPECT_FALSE(manifest->isFinalManifest())) {
+ _end++;
+ }
+
+ // Get final block number
+ is_final_block_number_discovered_ = true;
+ final_block_number_ = manifest->getFinalBlockNumber();
+
+ for (; _it != _end; _it++) {
+ suffix_hash_map_[_it->first] = std::make_pair(
+ std::vector<uint8_t>(_it->second, _it->second + 32),
+ manifest->getHashAlgorithm());
+ suffix_queue_.push(_it->first);
+ }
+
+ next_manifest_interval_ = manifest->getSuffixList().size();
+
+ if (manifest->isFinalManifest()) {
+ suffix_queue_completed_ = true;
+ // Give it a try
+ if (verifier_thread_) {
+ asio::io_service &io_service = portal_->getIoService();
+ io_service.post([this]() { scheduleNextInterests(); });
+ }
+ }
+
+ break;
+ }
+ case core::ManifestType::FLIC_MANIFEST: {
+ throw errors::NotImplementedException();
+ }
+ case core::ManifestType::FINAL_CHUNK_NUMBER: {
+ throw errors::NotImplementedException();
+ }
+ }
+ }
+
+ if (!socket_->virtual_download_) {
+ receive_buffer_.emplace(
+ std::make_pair(segment, std::move(manifest->getPacket())));
+ reassemble();
+ } else {
+ if (segment >= final_block_number_) {
+ stop();
+ }
+ }
+ }
+}
+
+bool VegasTransportProtocol::verifyManifest(
+ const ContentObjectManifest &manifest) {
+ if (!socket_->verify_signature_) {
+ return true;
+ }
+
+ bool is_data_secure = false;
+
+ if (socket_->on_content_object_verification_ == VOID_HANDLER) {
+ is_data_secure = static_cast<bool>(socket_->verifier_.verify(manifest));
+ } else if (socket_->on_content_object_verification_(*socket_, manifest)) {
+ is_data_secure = true;
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(!is_data_secure)) {
+ TRANSPORT_LOGE("Verification failed for %s\n",
+ manifest.getName().toString().c_str());
+ }
+
+ return is_data_secure;
+}
+
+// TODO Add the name in the digest computation!
+void VegasTransportProtocol::onContentObject(
+ Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+ uint32_t incremental_suffix = content_object->getName().getSuffix();
+
+ std::chrono::microseconds rtt;
+ Time now = std::chrono::steady_clock::now();
+ std::chrono::steady_clock::duration duration =
+ now - interest_timepoints_[incremental_suffix & mask_];
+ rtt = std::chrono::duration_cast<std::chrono::microseconds>(duration);
+
+ average_rtt_ = (0.7 * average_rtt_) + (0.3 * (double)rtt.count());
+
+ if (socket_->on_timer_expires_ != VOID_HANDLER) {
+ auto dt = std::chrono::duration_cast<TimeDuration>(now - socket_->t0_);
+ if (dt.count() > socket_->timer_interval_milliseconds_) {
+ socket_->on_timer_expires_(*socket_, byte_count_, dt,
+ current_window_size_, retx_count_,
+ std::round(average_rtt_));
+ socket_->t0_ = std::chrono::steady_clock::now();
+ }
+ }
+
+ interests_in_flight_--;
+
+ if (TRANSPORT_EXPECT_FALSE(!is_running_ || incremental_suffix == ~0_U64 ||
+ receive_buffer_.find(incremental_suffix) !=
+ receive_buffer_.end())) {
+ return;
+ }
+
+ changeInterestLifetime(incremental_suffix);
+
+ if (socket_->on_content_object_input_ != VOID_HANDLER) {
+ socket_->on_content_object_input_(*socket_, *content_object);
+ }
+
+ if (socket_->on_interest_satisfied_ != VOID_HANDLER) {
+ socket_->on_interest_satisfied_(*socket_, *interest);
+ }
+
+ if (!interest_retransmissions_[incremental_suffix & mask_]) {
+ afterContentReception(*interest, *content_object);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(content_object->getPayloadType() ==
+ PayloadType::MANIFEST)) {
+ // TODO Fix manifest!!
+ auto manifest =
+ std::make_unique<ContentObjectManifest>(std::move(content_object));
+
+ if (verifier_thread_ && incremental_suffix != 0) {
+ // verifier_thread_->add(std::bind(&VegasTransportProtocol::onManifest,
+ // this, std::move(manifest)));
+ } else {
+ onManifest(std::move(manifest));
+ }
+ } else if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) {
+ if (verifier_thread_) {
+ // verifier_thread_->add(std::bind(&VegasTransportProtocol::onContentSegment,
+ // this, std::move(content_object)));
+ } else {
+ onContentSegment(std::move(interest), std::move(content_object));
+ }
+ }
+
+ scheduleNextInterests();
+}
+
+bool VegasTransportProtocol::verifyContentObject(
+ const ContentObject &content_object) {
+ if (!dynamic_cast<ConsumerSocket *>(socket_)->verify_signature_) {
+ return true;
+ }
+
+ uint64_t segment = content_object.getName().getSuffix();
+
+ bool ret = false;
+
+ if (download_with_manifest_) {
+ auto it = suffix_hash_map_.find(segment);
+ if (it != suffix_hash_map_.end()) {
+ auto hash_type = static_cast<utils::CryptoHashType>(it->second.second);
+ auto data_packet_digest = content_object.computeDigest(it->second.second);
+ auto data_packet_digest_bytes =
+ data_packet_digest.getDigest<uint8_t>().data();
+ std::vector<uint8_t> &manifest_digest_bytes = it->second.first;
+
+ if (utils::CryptoHash::compareBinaryDigest(data_packet_digest_bytes,
+ manifest_digest_bytes.data(),
+ hash_type)) {
+ suffix_hash_map_.erase(it);
+ ret = true;
+ } else {
+ throw errors::RuntimeException(
+ "Verification failure policy has to be implemented.");
+ }
+ }
+ } else {
+ ret = static_cast<bool>(
+ dynamic_cast<ConsumerSocket *>(socket_)->verifier_.verify(
+ content_object));
+
+ if (!ret) {
+ throw errors::RuntimeException(
+ "Verification failure policy has to be implemented.");
+ }
+ }
+
+ return ret;
+ ;
+}
+
+void VegasTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+ TRANSPORT_LOGW("Timeout on %s", interest->getName().toString().c_str());
+
+ if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ return;
+ }
+
+ interests_in_flight_--;
+
+ uint64_t segment = interest->getName().getSuffix();
+
+ // Do not retransmit interests asking contents that do not exist.
+ if (is_final_block_number_discovered_) {
+ if (segment > final_block_number_) {
+ return;
+ }
+ }
+
+ if (socket_->on_interest_timeout_ != VOID_HANDLER) {
+ socket_->on_interest_timeout_(*socket_, *interest);
+ }
+
+ afterDataUnsatisfied(segment);
+
+ if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask_] <
+ socket_->max_retransmissions_)) {
+ retx_count_++;
+
+ if (socket_->on_interest_retransmission_ != VOID_HANDLER) {
+ socket_->on_interest_retransmission_(*socket_, *interest);
+ }
+
+ if (socket_->on_interest_output_ != VOID_HANDLER) {
+ socket_->on_interest_output_(*socket_, *interest);
+ }
+
+ if (!is_running_) {
+ return;
+ }
+
+ // retransmit
+ interests_in_flight_++;
+ interest_retransmissions_[segment & mask_]++;
+
+ using namespace std::placeholders;
+ portal_->sendInterest(std::move(interest));
+ } else {
+ TRANSPORT_LOGE("Stop: reached max retx limit.");
+ partialDownload();
+ stop();
+ }
+}
+
+void VegasTransportProtocol::copyContent(const ContentObject &content_object) {
+ Array a = content_object.getPayload();
+
+ content_buffer_->insert(content_buffer_->end(), (uint8_t *)a.data(),
+ (uint8_t *)a.data() + a.length());
+
+ bool download_completed =
+ is_final_block_number_discovered_ &&
+ content_object.getName().getSuffix() == final_block_number_;
+
+ if (TRANSPORT_EXPECT_FALSE(download_completed || !is_running_)) {
+ // asio::io_service& io_service = portal_->getIoService();
+ // io_service.post([this] () {
+ returnContentToUser();
+ // });
+ }
+}
+
+void VegasTransportProtocol::reassemble() {
+ uint64_t index = last_reassembled_segment_;
+ auto it = receive_buffer_.find(index);
+
+ do {
+ if (it->second->getPayloadType() == PayloadType::CONTENT_OBJECT) {
+ copyContent(*it->second);
+ receive_buffer_.erase(it);
+ }
+
+ index = ++last_reassembled_segment_;
+ it = receive_buffer_.find(index);
+ } while (it != receive_buffer_.end());
+}
+
+void VegasTransportProtocol::partialDownload() {
+ if (!socket_->virtual_download_) {
+ reassemble();
+ }
+
+ if (socket_->on_payload_retrieved_ != VOID_HANDLER) {
+ socket_->on_payload_retrieved_(
+ *socket_, byte_count_,
+ std::make_error_code(std::errc(std::errc::io_error)));
+ }
+}
+
+// TODO Check vegas protocol
+// void VegasTransportProtocol::checkForFastRetransmission(const Interest
+// &interest) {
+// uint64_t segNumber = interest.getName().getSuffix();
+// received_segments_[segNumber] = true;
+// fast_retransmitted_segments.erase(segNumber);
+
+// uint64_t possibly_lost_segment = 0;
+// uint64_t highest_received_segment = received_segments_.rbegin()->first;
+
+// for (uint64_t i = 0; i <= highest_received_segment; i++) {
+// if (received_segments_.find(i) == received_segments_.end()) {
+// if (fast_retransmitted_segments.find(i) ==
+// fast_retransmitted_segments.end()) {
+// possibly_lost_segment = i;
+// uint8_t out_of_order_segments = 0;
+// for (uint64_t j = i; j <= highest_received_segment; j++) {
+// if (received_segments_.find(j) != received_segments_.end()) {
+// out_of_order_segments++;
+// if (out_of_order_segments >=
+// default_values::max_out_of_order_segments) {
+// fast_retransmitted_segments[possibly_lost_segment] = true;
+// fastRetransmit(interest, possibly_lost_segment);
+// }
+// }
+// }
+// }
+// }
+// }
+// }
+
+// void VegasTransportProtocol::fastRetransmit(const Interest &interest,
+// uint32_t chunk_number) {
+// if (interest_retransmissions_[chunk_number & mask_] <
+// socket_->max_retransmissions_) {
+// Name name = interest.getName();
+// name.setSuffix(chunk_number);
+
+// std::shared_ptr<Interest> retx_interest =
+// std::make_shared<Interest>(name);
+
+// if (socket_->on_interest_retransmission_ != VOID_HANDLER) {
+// socket_->on_interest_retransmission_(*socket_, *retx_interest);
+// }
+
+// if (socket_->on_interest_output_ != VOID_HANDLER) {
+// socket_->on_interest_output_(*socket_, *retx_interest);
+// }
+
+// if (!is_running_) {
+// return;
+// }
+
+// interests_in_flight_++;
+// interest_retransmissions_[chunk_number & mask_]++;
+
+// using namespace std::placeholders;
+// portal_->sendInterest(std::move(retx_interest));
+// }
+// }
+
+void VegasTransportProtocol::removeAllPendingInterests() { portal_->clear(); }
+
+} // end namespace protocol
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/vegas.h b/libtransport/src/hicn/transport/protocols/vegas.h
new file mode 100755
index 000000000..7791ffc94
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/vegas.h
@@ -0,0 +1,161 @@
+/*
+ * 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/protocols/protocol.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/ring_buffer.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+
+namespace transport {
+
+namespace protocol {
+
+typedef utils::CircularFifo<uint32_t, 1024 * 128> SuffixQueue;
+typedef std::chrono::time_point<std::chrono::steady_clock> Time;
+typedef std::chrono::milliseconds TimeDuration;
+
+class VegasTransportProtocol : public TransportProtocol {
+ public:
+ VegasTransportProtocol(interface::BaseSocket *icnet_socket);
+
+ virtual ~VegasTransportProtocol();
+
+ virtual void start(utils::SharableVector<uint8_t> &content_buffer) override;
+
+ void stop() override;
+
+ void resume() override;
+
+ protected:
+ void reset();
+
+ void sendInterest(std::uint64_t next_suffix);
+
+ void onContentSegment(Interest::Ptr &&interest,
+ ContentObject::Ptr &&content_object);
+
+ bool verifyContentObject(const ContentObject &content_object);
+
+ bool verifyManifest(const interface::ContentObjectManifest &manifest);
+
+ virtual void onTimeout(Interest::Ptr &&interest) override;
+
+ void onManifest(std::unique_ptr<interface::ContentObjectManifest> &&manifest);
+
+ void onContentObject(Interest::Ptr &&interest,
+ ContentObject::Ptr &&content_object) override;
+
+ virtual void changeInterestLifetime(uint64_t segment);
+
+ void scheduleNextInterests();
+
+ virtual void decreaseWindow();
+
+ virtual void increaseWindow();
+
+ virtual void afterContentReception(const Interest &interest,
+ const ContentObject &content_object);
+
+ virtual void afterDataUnsatisfied(uint64_t segment);
+
+ void reassemble();
+
+ void returnContentToUser();
+
+ void partialDownload();
+
+ virtual void copyContent(const ContentObject &content_object);
+
+ // virtual void checkForFastRetransmission(const Interest &interest);
+
+ // void fastRetransmit(const Interest &interest, uint32_t chunk_number);
+
+ void removeAllPendingInterests();
+
+ protected:
+ void handleTimeout(const std::error_code &ec);
+
+ // reassembly variables
+ volatile bool is_final_block_number_discovered_;
+ std::atomic<uint64_t> final_block_number_;
+ uint64_t last_reassembled_segment_;
+ std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+ size_t content_buffer_size_;
+
+ // transmission variablesis_final_block_number_discovered_
+ double current_window_size_;
+ double pending_window_size_;
+ uint64_t interests_in_flight_;
+ uint64_t next_suffix_;
+ std::vector<std::uint32_t> interest_retransmissions_;
+ std::vector<std::chrono::steady_clock::time_point> interest_timepoints_;
+ RtoEstimator rtt_estimator_;
+
+ uint32_t retx_count_;
+
+ // buffers
+ std::unordered_map<std::uint32_t, ContentObject::Ptr>
+ receive_buffer_; // verified segments by segment number
+ std::unordered_map<std::uint32_t, ContentObject::Ptr>
+ unverified_segments_; // used with embedded manifests
+ std::unordered_map<std::uint32_t, ContentObject::Ptr>
+ verified_manifests_; // by segment number
+
+ std::uint16_t interest_pool_index_;
+ std::uint16_t mask_;
+
+ // suffix randomization: since the suffixes in the manifests could not be in a
+ // sequential order, we need to map those suffixes into an ordered sequence.
+ std::unordered_map<std::uint64_t, std::uint64_t>
+ incremental_suffix_to_real_suffix_map_;
+ std::unordered_map<std::uint64_t, std::uint64_t>
+ real_suffix_to_incremental_suffix_map_;
+ std::uint32_t incremental_suffix_index_;
+
+ // verification
+ std::unordered_map<uint32_t, std::pair<std::vector<uint8_t>, HashAlgorithm>>
+ suffix_hash_map_;
+
+ // Fast Retransmission
+ std::map<uint64_t, bool> received_segments_;
+ std::unordered_map<uint64_t, bool> fast_retransmitted_segments;
+
+ // Suffix queue
+ volatile bool suffix_queue_completed_;
+ SuffixQueue suffix_queue_;
+
+ volatile bool download_with_manifest_;
+ uint32_t next_manifest_;
+ std::atomic<uint16_t> next_manifest_interval_;
+
+ std::unique_ptr<utils::EventThread> verifier_thread_;
+
+ uint32_t interest_tx_;
+ uint32_t interest_count_;
+
+ uint64_t byte_count_;
+ double average_rtt_;
+
+ std::unordered_map<uint32_t, uint64_t> sign_time_;
+};
+
+} // namespace protocol
+
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc
new file mode 100755
index 000000000..f5f797bbe
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.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/interfaces/socket_options_default_values.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+#include <algorithm>
+#include <cmath>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RtoEstimator::RtoEstimator(Duration min_rto)
+ : smoothed_rtt_(RtoEstimator::getInitialRtt().count()),
+ rtt_variation_(0),
+ first_measurement_(true),
+ last_rto_(min_rto.count()) {}
+
+void RtoEstimator::addMeasurement(Duration rtt) {
+ double duration = static_cast<double>(rtt.count());
+ if (first_measurement_) {
+ smoothed_rtt_ = duration;
+ rtt_variation_ = duration / 2;
+ first_measurement_ = false;
+ } else {
+ rtt_variation_ = (1 - default_values::beta) * rtt_variation_ +
+ default_values::beta * std::abs(smoothed_rtt_ - duration);
+ smoothed_rtt_ = (1 - default_values::alpha) * smoothed_rtt_ +
+ default_values::alpha * duration;
+ }
+}
+
+RtoEstimator::Duration RtoEstimator::computeRto() const {
+ double rto = smoothed_rtt_ +
+ std::max(double(default_values::clock_granularity.count()),
+ default_values::k* rtt_variation_);
+ return Duration(static_cast<Duration::rep>(rto));
+}
+
+} // end namespace protocol
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.h b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.h
new file mode 100755
index 000000000..e84afc49c
--- /dev/null
+++ b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.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 <chrono>
+
+// Implementation inspired from RFC6298
+// (https://tools.ietf.org/search/rfc6298#ref-JK88)
+
+namespace transport {
+
+namespace protocol {
+
+class RtoEstimator {
+ public:
+ typedef std::chrono::microseconds Duration;
+
+ static Duration getInitialRtt() { return std::chrono::seconds(1); }
+
+ RtoEstimator(Duration min_rto = std::chrono::seconds(1));
+
+ void addMeasurement(Duration measure);
+
+ Duration computeRto() const;
+
+ private:
+ double smoothed_rtt_;
+ double rtt_variation_;
+ bool first_measurement_;
+ double last_rto_;
+};
+
+} // end namespace protocol
+
+} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/CMakeLists.txt b/libtransport/src/hicn/transport/utils/CMakeLists.txt
new file mode 100755
index 000000000..088fb5862
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/CMakeLists.txt
@@ -0,0 +1,76 @@
+# 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 SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/uri.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/log.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/membuf.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_store.cc
+)
+
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/array.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hash.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/uri.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/sharable_vector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/branch_prediction.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/deadline_timer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ring_buffer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/stream_buffer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/endianess.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/literals.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/signer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/verifier.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hasher.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash_type.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/identity.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/conversions.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/linux.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/log.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/event_thread.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/object_pool.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/membuf.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/spinlock.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/key_id.h
+)
+
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fd_deadline_timer.h
+ )
+
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.cc
+ )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/hicn/transport/utils/array.h b/libtransport/src/hicn/transport/utils/array.h
new file mode 100755
index 000000000..a3a66e498
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/array.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <cstddef>
+
+namespace utils {
+
+template <typename T>
+class Array {
+ public:
+ explicit Array(const T *array, size_t size) : array_(array), size_(size) {
+ this->array_ = array;
+ this->size_ = size;
+ }
+
+ Array() : array_(nullptr), size_(0) {
+ this->array_ = nullptr;
+ this->size_ = 0;
+ }
+
+ TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; }
+
+ TRANSPORT_ALWAYS_INLINE T *writableData() const {
+ return const_cast<T *>(array_);
+ }
+
+ TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; }
+
+ TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) {
+ array_ = data;
+ return *this;
+ }
+
+ TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) {
+ size_ = size;
+ return *this;
+ }
+
+ TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; }
+
+ private:
+ const T *array_;
+ std::size_t size_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/branch_prediction.h b/libtransport/src/hicn/transport/utils/branch_prediction.h
new file mode 100755
index 000000000..b12282fe8
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/branch_prediction.h
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+#undef TRANSPORT_EXPECT_TRUE
+#undef TRANSPORT_EXPECT_FALSE
+
+#define TRANSPORT_EXPECT_TRUE(x) __builtin_expect((x), 1)
+#define TRANSPORT_EXPECT_FALSE(x) __builtin_expect((x), 0) \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/content_store.cc b/libtransport/src/hicn/transport/utils/content_store.cc
new file mode 100755
index 000000000..4c7637dad
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/content_store.cc
@@ -0,0 +1,109 @@
+/*
+ * 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/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/content_store.h>
+
+namespace utils {
+
+ContentStore::ContentStore(std::size_t max_packets)
+ : max_content_store_size_(max_packets) {}
+
+ContentStore::~ContentStore() {}
+
+void ContentStore::insert(
+ const std::shared_ptr<ContentObject> &content_object) {
+ if (max_content_store_size_ == 0) {
+ return;
+ }
+
+ std::unique_lock<std::mutex> lock(cs_mutex_);
+
+ if (TRANSPORT_EXPECT_FALSE(content_store_hash_table_.size() !=
+ lru_list_.size())) {
+ TRANSPORT_LOGW("Inconsistent size!!!!");
+ TRANSPORT_LOGW("Hash Table: %zu |||| FIFO List: %zu",
+ content_store_hash_table_.size(), lru_list_.size());
+ }
+
+ // Check if the content can be cached
+ if (content_object->getLifetime() > 0) {
+ if (content_store_hash_table_.size() >= max_content_store_size_) {
+ content_store_hash_table_.erase(lru_list_.back());
+ lru_list_.pop_back();
+ }
+
+ // Insert new item
+
+ auto it = content_store_hash_table_.find(content_object->getName());
+ if (it != content_store_hash_table_.end()) {
+ lru_list_.erase(it->second.second);
+ content_store_hash_table_.erase(content_object->getName());
+ }
+
+ lru_list_.push_front(std::cref(content_object->getName()));
+ auto pos = lru_list_.begin();
+ content_store_hash_table_[content_object->getName()] = ContentStoreEntry(
+ ObjectTimeEntry(content_object, std::chrono::steady_clock::now()), pos);
+ }
+}
+
+const std::shared_ptr<ContentObject> &ContentStore::find(
+ const Interest &interest) {
+ std::unique_lock<std::mutex> lock(cs_mutex_);
+ auto it = content_store_hash_table_.find(interest.getName());
+ if (it != content_store_hash_table_.end()) {
+ // if (std::chrono::duration_cast<std::chrono::milliseconds>(
+ // std::chrono::steady_clock::now() - it->second.first.second).count()
+ // < it->second.first.first->getLifetime() ||
+ // it->second.first.first->getLifetime() ==
+ // default_values::never_expire_time) {
+ return it->second.first.first;
+ // }
+ }
+
+ return empty_reference_;
+}
+
+void ContentStore::erase(const Name &exact_name) {
+ std::unique_lock<std::mutex> lock(cs_mutex_);
+ auto it = content_store_hash_table_.find(exact_name);
+ lru_list_.erase(it->second.second);
+ content_store_hash_table_.erase(exact_name);
+}
+
+void ContentStore::setLimit(size_t max_packets) {
+ max_content_store_size_ = max_packets;
+}
+
+std::size_t ContentStore::getLimit() const { return max_content_store_size_; }
+
+std::size_t ContentStore::size() const {
+ return content_store_hash_table_.size();
+}
+
+void ContentStore::printContent() {
+ for (auto &item : content_store_hash_table_) {
+ if (item.second.first.first->getPayloadType() ==
+ transport::core::PayloadType::MANIFEST) {
+ TRANSPORT_LOGI("Manifest: %s\n",
+ item.second.first.first->getName().toString().c_str());
+ }
+ }
+}
+
+} // end namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/content_store.h b/libtransport/src/hicn/transport/utils/content_store.h
new file mode 100755
index 000000000..ab4963fff
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/content_store.h
@@ -0,0 +1,75 @@
+/*
+ * 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/interfaces/socket.h>
+
+#include <mutex>
+
+namespace transport {
+
+namespace core {
+class Name;
+class ContentObject;
+class Interest;
+} // namespace core
+
+} // namespace transport
+
+namespace utils {
+
+using Name = transport::core::Name;
+using ContentObject = transport::core::ContentObject;
+using Interest = transport::core::Interest;
+
+typedef std::pair<std::shared_ptr<ContentObject>,
+ std::chrono::steady_clock::time_point>
+ ObjectTimeEntry;
+typedef std::pair<ObjectTimeEntry,
+ std::list<std::reference_wrapper<const Name>>::iterator>
+ ContentStoreEntry;
+typedef std::list<std::reference_wrapper<const Name>> LRUList;
+typedef std::unordered_map<Name, ContentStoreEntry> ContentStoreHashTable;
+
+class ContentStore {
+ public:
+ explicit ContentStore(std::size_t max_packets = 65536);
+
+ ~ContentStore();
+
+ void insert(const std::shared_ptr<ContentObject> &content_object);
+
+ const std::shared_ptr<ContentObject> &find(const Interest &interest);
+
+ void erase(const Name &exact_name);
+
+ void setLimit(size_t max_packets);
+
+ size_t getLimit() const;
+
+ size_t size() const;
+
+ void printContent();
+
+ private:
+ ContentStoreHashTable content_store_hash_table_;
+ LRUList lru_list_;
+ std::shared_ptr<ContentObject> empty_reference_;
+ std::size_t max_content_store_size_;
+ std::mutex cs_mutex_;
+};
+
+} // end namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/conversions.h b/libtransport/src/hicn/transport/utils/conversions.h
new file mode 100755
index 000000000..24b529206
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/conversions.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <stdio.h>
+#include <cstdint>
+#include <string>
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress(
+ const std::string& mac_address, uint8_t* mac_byte_array) {
+ const char* mac = mac_address.c_str();
+
+ sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0],
+ &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3],
+ &mac_byte_array[4], &mac_byte_array[5]);
+
+ return 0;
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hash.h b/libtransport/src/hicn/transport/utils/crypto_hash.h
new file mode 100755
index 000000000..0c15c8bda
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/crypto_hash.h
@@ -0,0 +1,115 @@
+/*
+ * 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/errors/runtime_exception.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/array.h>
+#include <hicn/transport/utils/crypto_hash_type.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHash.h>
+};
+
+#include <cstring>
+#include <unordered_map>
+
+namespace utils {
+
+class CryptoHasher;
+
+struct EnumClassHash {
+ template <typename T>
+ std::size_t operator()(T t) const {
+ return static_cast<std::size_t>(t);
+ }
+};
+
+static std::unordered_map<CryptoHashType, std::size_t, EnumClassHash>
+ hash_size_map = {{CryptoHashType::SHA_256, 32},
+ {CryptoHashType::CRC32C, 4},
+ {CryptoHashType::SHA_512, 64}};
+
+class Signer;
+class Verifier;
+
+class CryptoHash {
+ friend class CryptoHasher;
+ friend class Signer;
+ friend class Verifier;
+
+ public:
+ CryptoHash() : hash_(nullptr) {}
+
+ CryptoHash(const CryptoHash& other) {
+ if (other.hash_) {
+ hash_ = parcCryptoHash_Acquire(other.hash_);
+ }
+ }
+
+ CryptoHash(CryptoHash&& other) {
+ if (other.hash_) {
+ hash_ = parcCryptoHash_Acquire(other.hash_);
+ }
+ }
+
+ template <typename T>
+ CryptoHash(const T* buffer, std::size_t length, CryptoHashType hash_type) {
+ hash_ = parcCryptoHash_CreateFromArray(
+ static_cast<PARCCryptoHashType>(hash_type), buffer, length);
+ }
+
+ ~CryptoHash() {
+ if (hash_) {
+ parcCryptoHash_Release(&hash_);
+ }
+ }
+
+ CryptoHash& operator=(const CryptoHash& other) {
+ if (other.hash_) {
+ hash_ = parcCryptoHash_Acquire(other.hash_);
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ utils::Array<T> getDigest() const {
+ return utils::Array<T>(
+ static_cast<T*>(parcBuffer_Overlay(parcCryptoHash_GetDigest(hash_), 0)),
+ parcBuffer_Remaining(parcCryptoHash_GetDigest(hash_)));
+ }
+
+ CryptoHashType getType() {
+ return static_cast<CryptoHashType>(parcCryptoHash_GetDigestType(hash_));
+ }
+
+ template <typename T>
+ static bool compareBinaryDigest(const T* digest1, const T* digest2,
+ CryptoHashType hash_type) {
+ if (hash_size_map.find(hash_type) == hash_size_map.end()) {
+ return false;
+ }
+
+ return !static_cast<bool>(
+ std::memcmp(digest1, digest2, hash_size_map[hash_type]));
+ }
+
+ private:
+ PARCCryptoHash* hash_;
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hash_type.h b/libtransport/src/hicn/transport/utils/crypto_hash_type.h
new file mode 100755
index 000000000..b7597e208
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/crypto_hash_type.h
@@ -0,0 +1,31 @@
+/*
+ * 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
+
+extern "C" {
+#include <parc/security/parc_CryptoHashType.h>
+};
+
+namespace utils {
+
+enum class CryptoHashType : uint8_t {
+ SHA_256 = PARCCryptoHashType_SHA256,
+ SHA_512 = PARCCryptoHashType_SHA512,
+ CRC32C = PARCCryptoHashType_CRC32C,
+ NULL_HASH = PARCCryptoHashType_NULL
+};
+
+} \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hasher.h b/libtransport/src/hicn/transport/utils/crypto_hasher.h
new file mode 100755
index 000000000..c34a26fac
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/crypto_hasher.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/utils/crypto_hash.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHasher.h>
+};
+
+namespace utils {
+
+class CryptoHasher {
+ public:
+ CryptoHasher(CryptoHashType hash_type)
+ : hasher_(parcCryptoHasher_Create(
+ static_cast<PARCCryptoHashType>(hash_type))),
+ managed_(true) {}
+
+ CryptoHasher(PARCCryptoHasher* hasher) : hasher_(hasher), managed_(false) {}
+
+ ~CryptoHasher() {
+ if (managed_) {
+ parcCryptoHasher_Release(&hasher_);
+ }
+ }
+
+ CryptoHasher& init() {
+ if (parcCryptoHasher_Init(hasher_) == -1) {
+ throw errors::RuntimeException("Cryptohash init failed.");
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ CryptoHasher& updateBytes(const T* buffer, std::size_t length) {
+ if (parcCryptoHasher_UpdateBytes(hasher_, buffer, length) == -1) {
+ throw errors::RuntimeException("Cryptohash updateBytes failed.");
+ }
+ return *this;
+ }
+
+ CryptoHash finalize() {
+ CryptoHash hash;
+ hash.hash_ = parcCryptoHasher_Finalize(hasher_);
+ return hash;
+ }
+
+ private:
+ PARCCryptoHasher* hasher_;
+ bool managed_;
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_suite.h b/libtransport/src/hicn/transport/utils/crypto_suite.h
new file mode 100755
index 000000000..8ae32b846
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/crypto_suite.h
@@ -0,0 +1,35 @@
+/*
+ * 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
+
+extern "C" {
+#include <parc/security/parc_CryptoSuite.h>
+};
+
+namespace utils {
+
+enum class CryptoSuite : uint8_t {
+ RSA_SHA256 = PARCCryptoSuite_RSA_SHA256,
+ DSA_SHA256 = PARCCryptoSuite_DSA_SHA256,
+ RSA_SHA512 = PARCCryptoSuite_RSA_SHA512,
+ HMAC_SHA256 = PARCCryptoSuite_HMAC_SHA256,
+ HMAC_SHA512 = PARCCryptoSuite_HMAC_SHA512,
+ NULL_CRC32C = PARCCryptoSuite_NULL_CRC32C,
+ ECDSA_256K1 = PARCCryptoSuite_ECDSA_SHA256,
+ UNKNOWN = PARCCryptoSuite_UNKNOWN
+};
+
+}
diff --git a/libtransport/src/hicn/transport/utils/daemonizator.cc b/libtransport/src/hicn/transport/utils/daemonizator.cc
new file mode 100755
index 000000000..d9b3109af
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/daemonizator.cc
@@ -0,0 +1,73 @@
+/*
+ * 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/errors/runtime_exception.h>
+#include <hicn/transport/utils/daemonizator.h>
+#include <hicn/transport/utils/log.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace utils {
+
+void Daemonizator::daemonize(bool close_fds) {
+ pid_t process_id = 0;
+ pid_t sid = 0;
+
+ // Create child process
+ process_id = fork();
+
+ // Indication of fork() failure
+ if (process_id < 0) {
+ throw errors::RuntimeException("Fork failed.");
+ }
+
+ // PARENT PROCESS. Need to kill it.
+ if (process_id > 0) {
+ TRANSPORT_LOGE("Process id of child process %d", process_id);
+ // return success in exit status
+ exit(EXIT_SUCCESS);
+ }
+
+ // unmask the file mode
+ umask(0);
+
+ // set new session
+ sid = setsid();
+ if (sid < 0) {
+ // Return failure
+ exit(EXIT_FAILURE);
+ }
+
+ // Change the current working directory to root.
+ int ret = chdir("/");
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error changing working directory to root");
+ }
+
+ // Close stdin. Redirect stdout and stderr to file if possible
+
+ if (close_fds) {
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ }
+
+ close(STDIN_FILENO);
+
+ // Really start application
+}
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/daemonizator.h b/libtransport/src/hicn/transport/utils/daemonizator.h
new file mode 100755
index 000000000..a21ce8a7b
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/daemonizator.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <cstdlib>
+namespace utils {
+
+class Daemonizator {
+ public:
+ static void daemonize(bool close_fds = true);
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/deadline_timer.h b/libtransport/src/hicn/transport/utils/deadline_timer.h
new file mode 100755
index 000000000..61f906141
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/deadline_timer.h
@@ -0,0 +1,114 @@
+/*
+ * 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/utils/event_reactor.h>
+
+#include <chrono>
+#include <cstddef>
+#include <cstring>
+#include <utility>
+
+namespace std {
+namespace chrono {
+namespace detail {
+
+template <typename From, typename To>
+struct posix_duration_cast;
+
+// chrono -> timespec caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<std::chrono::duration<Rep, Period>,
+ struct timespec> {
+ static struct timespec cast(std::chrono::duration<Rep, Period> const &d) {
+ struct timespec tv;
+
+ std::chrono::seconds const sec =
+ std::chrono::duration_cast<std::chrono::seconds>(d);
+
+ tv.tv_sec = sec.count();
+ tv.tv_nsec =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count();
+
+ return tv;
+ }
+};
+
+// timespec -> chrono caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<struct timespec,
+ std::chrono::duration<Rep, Period>> {
+ static std::chrono::duration<Rep, Period> cast(struct timespec const &tv) {
+ return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
+ std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec));
+ }
+};
+
+} // namespace detail
+
+// chrono -> timespec
+template <typename T, typename Rep, typename Period>
+auto duration_cast(std::chrono::duration<Rep, Period> const &d) ->
+ typename std::enable_if<std::is_same<T, struct timespec>::value,
+ struct timespec>::type {
+ return detail::posix_duration_cast<std::chrono::duration<Rep, Period>,
+ timespec>::cast(d);
+}
+
+// timespec -> chrono
+template <typename Duration>
+Duration duration_cast(struct timespec const &tv) {
+ return detail::posix_duration_cast<struct timespec, Duration>::cast(tv);
+}
+
+} // namespace chrono
+} // namespace std
+
+namespace utils {
+
+template <typename Implementation>
+class DeadlineTimer {
+ public:
+ virtual ~DeadlineTimer() = default;
+
+ template <typename WaitHandler>
+ void asyncWait(WaitHandler &&callback) {
+ static_cast<Implementation *>(this)->asyncWaitImpl(
+ std::forward<WaitHandler>(callback));
+ }
+
+ void wait() { static_cast<Implementation *>(this)->waitImpl(); }
+
+ template <typename T, typename R>
+ void expiresFromNow(std::chrono::duration<T, R> &&duration) {
+ static_cast<Implementation *>(this)->expiresFromNowImpl(
+ std::forward<std::chrono::duration<T, R>>(duration));
+ }
+
+ template <typename TimePoint,
+ typename = typename std::enable_if<
+ std::is_same<std::remove_reference_t<TimePoint>,
+ std::chrono::steady_clock::time_point>::value,
+ TimePoint>::type>
+ void expiresAt(TimePoint &&time_point) {
+ static_cast<Implementation *>(this)->expiresAtImpl(
+ std::forward<TimePoint>(time_point));
+ }
+
+ void cancel() { static_cast<Implementation *>(this)->cancelImpl(); }
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/endianess.h b/libtransport/src/hicn/transport/utils/endianess.h
new file mode 100755
index 000000000..a3ec21c90
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/endianess.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/portability/portability.h>
+
+#include <arpa/inet.h>
+#include <cstring>
+
+namespace utils {
+
+namespace {
+
+template <size_t Size>
+struct uint_types_by_size;
+
+#define GENERATOR(sz, fn) \
+ static TRANSPORT_ALWAYS_INLINE uint##sz##_t byteswap_gen(uint##sz##_t v) { \
+ return fn(v); \
+ } \
+ template <> \
+ struct uint_types_by_size<sz / 8> { \
+ using type = uint##sz##_t; \
+ };
+
+GENERATOR(8, uint8_t)
+#ifdef _MSC_VER
+GENERATOR(64, _byteswap_uint64)
+GENERATOR(32, _byteswap_ulong)
+GENERATOR(16, _byteswap_ushort)
+#else
+GENERATOR(64, __builtin_bswap64)
+GENERATOR(32, __builtin_bswap32)
+GENERATOR(16, __builtin_bswap16)
+#endif
+
+template <typename T>
+struct EndianInt {
+ static_assert(
+ (std::is_integral<T>::value && !std::is_same<T, bool>::value) ||
+ std::is_floating_point<T>::value,
+ "template type parameter must be non-bool integral or floating point");
+
+ static T swap(T x) {
+ // we implement this with memcpy because that is defined behavior in C++
+ // we rely on compilers to optimize away the memcpy calls
+ constexpr auto s = sizeof(T);
+ using B = typename uint_types_by_size<s>::type;
+ B b;
+ std::memcpy(&b, &x, s);
+ b = byteswap_gen(b);
+ std::memcpy(&x, &b, s);
+ return x;
+ }
+ static T big(T x) {
+ return portability::little_endian_arch ? EndianInt::swap(x) : x;
+ }
+ static T little(T x) {
+ return portability::big_endian_arch ? EndianInt::swap(x) : x;
+ }
+};
+
+} // namespace
+
+// big* convert between native and big-endian representations
+// little* convert between native and little-endian representations
+// swap* convert between big-endian and little-endian representations
+//
+// ntohs, htons == big16
+// ntohl, htonl == big32
+#define GENERATOR1(fn, t, sz) \
+ static t fn##sz(t x) { return fn<t>(x); }
+
+#define GENERATOR2(t, sz) \
+ GENERATOR1(swap, t, sz) \
+ GENERATOR1(big, t, sz) \
+ GENERATOR1(little, t, sz)
+
+#define GENERATOR3(sz) \
+ GENERATOR2(uint##sz##_t, sz) \
+ GENERATOR2(int##sz##_t, sz)
+
+class Endian {
+ public:
+ enum class Order : uint8_t { LITTLE, BIG };
+
+ static constexpr Order order =
+ portability::little_endian_arch ? Order::LITTLE : Order::BIG;
+
+ template <typename T>
+ static T swap(T x) {
+ return EndianInt<T>::swap(x);
+ }
+
+ template <typename T>
+ static T big(T x) {
+ return EndianInt<T>::big(x);
+ }
+
+ template <typename T>
+ static T little(T x) {
+ return EndianInt<T>::little(x);
+ }
+
+#if !defined(__ANDROID__)
+ GENERATOR3(64)
+ GENERATOR3(32)
+ GENERATOR3(16)
+ GENERATOR3(8)
+#endif
+};
+
+template <typename T>
+static TRANSPORT_ALWAYS_INLINE T ntoh(T x) {
+ return Endian::order == Endian::Order::LITTLE ? Endian::little(x) : x;
+}
+
+template <typename T>
+static TRANSPORT_ALWAYS_INLINE T hton(T x) {
+ return Endian::order == Endian::Order::LITTLE ? Endian::big(x) : x;
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc b/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc
new file mode 100755
index 000000000..81b471857
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc
@@ -0,0 +1,183 @@
+/*
+ * 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/utils/branch_prediction.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/fd_deadline_timer.h>
+
+#include <signal.h>
+#include <unistd.h>
+#include <iostream>
+
+namespace utils {
+
+EpollEventReactor::EpollEventReactor()
+ : epoll_fd_(epoll_create(20000)), run_event_loop_(true) {}
+
+EpollEventReactor::~EpollEventReactor() { close(epoll_fd_); }
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ TRANSPORT_LOGE("invalid fd %d", fd);
+ return -1;
+ }
+
+ struct epoll_event evt;
+ std::memset(&evt, 0, sizeof(evt));
+ evt.events = events;
+ evt.data.fd = fd;
+
+ if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &evt) <
+ 0)) {
+ TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events,
+ EventCallback &callback) {
+ auto it = event_callback_map_.find(fd);
+ event_callback_map_[fd] = callback;
+ if (it != event_callback_map_.end()) {
+ event_callback_map_[fd] = callback;
+ } else {
+ return addFileDescriptor(fd, events);
+ }
+
+ return 0;
+}
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events,
+ EventCallback &&callback) {
+ auto it = event_callback_map_.find(fd);
+ event_callback_map_[fd] = callback;
+ if (it != event_callback_map_.end()) {
+ event_callback_map_[fd] = callback;
+ } else {
+ return addFileDescriptor(fd, events);
+ }
+
+ return 0;
+}
+
+int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ TRANSPORT_LOGE("invalid fd %d", fd);
+ return -1;
+ }
+
+ struct epoll_event evt;
+ memset(&evt, 0, sizeof(evt));
+ evt.events = events;
+ evt.data.fd = fd;
+
+ if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) <
+ 0)) {
+ TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+std::size_t EpollEventReactor::mapSize() { return event_callback_map_.size(); }
+
+int EpollEventReactor::delFileDescriptor(int fd) {
+ if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+ TRANSPORT_LOGE("invalid fd %d", fd);
+ return -1;
+ }
+
+ struct epoll_event evt;
+ memset(&evt, 0, sizeof(evt));
+
+ if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &evt) <
+ 0)) {
+ TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ return -1;
+ }
+
+ event_callback_map_.erase(fd);
+
+ return 0;
+}
+
+void EpollEventReactor::runEventLoop(int timeout) {
+ Event evt[128];
+ int en = 0;
+
+ // evt.events = EPOLLIN | EPOLLOUT;
+ sigset_t sigset;
+ sigemptyset(&sigset);
+
+ while (run_event_loop_) {
+ memset(&evt, 0, sizeof(evt));
+
+ en = epoll_pwait(epoll_fd_, evt, 128, timeout, &sigset);
+
+ if (TRANSPORT_EXPECT_FALSE(en < 0)) {
+ TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+ return;
+ }
+
+ for (int i = 0; i < en; i++) {
+ if (evt[i].data.fd > 0) {
+ auto it = event_callback_map_.find(evt[i].data.fd);
+ if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
+ TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+ } else {
+ event_callback_map_[evt[i].data.fd](evt[i]);
+ }
+ } else {
+ TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+ }
+ }
+ }
+}
+
+void EpollEventReactor::runOneEvent() {
+ Event evt;
+ int en = 0;
+
+ // evt.events = EPOLLIN | EPOLLOUT;
+ sigset_t sigset;
+ sigemptyset(&sigset);
+
+ memset(&evt, 0, sizeof(evt));
+
+ en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset);
+
+ if (TRANSPORT_EXPECT_FALSE(en < 0)) {
+ TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+ return;
+ }
+
+ if (TRANSPORT_EXPECT_TRUE(evt.data.fd > 0)) {
+ auto it = event_callback_map_.find(evt.data.fd);
+ if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
+ TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+ } else {
+ event_callback_map_[evt.data.fd](evt);
+ }
+ } else {
+ TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+ }
+}
+
+void EpollEventReactor::stop() { run_event_loop_ = false; }
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.h b/libtransport/src/hicn/transport/utils/epoll_event_reactor.h
new file mode 100755
index 000000000..bb4db3ee7
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/epoll_event_reactor.h
@@ -0,0 +1,65 @@
+/*
+ * 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/utils/event_reactor.h>
+
+#include <sys/epoll.h>
+#include <cstddef>
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+
+#define FD_NUMBER 20000
+
+namespace utils {
+
+typedef struct epoll_event Event;
+typedef std::function<int(const Event &)> EventCallback;
+typedef std::unordered_map<int, EventCallback> EventCallbackMap;
+
+class EpollEventReactor : public EventReactor {
+ public:
+ explicit EpollEventReactor();
+
+ ~EpollEventReactor();
+
+ int addFileDescriptor(int fd, uint32_t events, EventCallback &callback);
+
+ int addFileDescriptor(int fd, uint32_t events, EventCallback &&callback);
+
+ int delFileDescriptor(int fd);
+
+ int modFileDescriptor(int fd, uint32_t events);
+
+ void runEventLoop(int timeout = -1) override;
+
+ void runOneEvent() override;
+
+ void stop() override;
+
+ std::size_t mapSize();
+
+ private:
+ int addFileDescriptor(int fd, uint32_t events);
+
+ int epoll_fd_;
+ volatile bool run_event_loop_;
+ EventCallbackMap event_callback_map_;
+ std::mutex event_callback_map_mutex_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/event_reactor.h b/libtransport/src/hicn/transport/utils/event_reactor.h
new file mode 100755
index 000000000..4f8b58296
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/event_reactor.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <cstddef>
+#include <functional>
+#include <system_error>
+
+namespace utils {
+
+typedef std::function<void(const std::error_code &ec)> UserCallback;
+
+class EventReactor {
+ public:
+ virtual ~EventReactor() = default;
+
+ virtual void runEventLoop(int timeout = -1) = 0;
+
+ virtual void runOneEvent() = 0;
+
+ virtual void stop() = 0;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/event_thread.h b/libtransport/src/hicn/transport/utils/event_thread.h
new file mode 100755
index 000000000..3bf08c94b
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/event_thread.h
@@ -0,0 +1,101 @@
+/*
+ * 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/errors/runtime_exception.h>
+#include <memory>
+
+#include <asio.hpp>
+
+namespace utils {
+
+class EventThread {
+ private:
+ // No copies
+ EventThread(const EventThread&) = delete; // non construction-copyable
+ EventThread& operator=(const EventThread&) = delete; // non copyable
+
+ public:
+ explicit EventThread(asio::io_service& io_service)
+ : internal_io_service_(nullptr),
+ io_service_(io_service),
+ work_(io_service_),
+ thread_(nullptr) {
+ run();
+ }
+
+ explicit EventThread()
+ : internal_io_service_(std::make_unique<asio::io_service>()),
+ io_service_(*internal_io_service_),
+ work_(io_service_),
+ thread_(nullptr) {
+ run();
+ }
+
+ ~EventThread() { stop(); }
+
+ void run() {
+ if (stopped()) {
+ io_service_.reset();
+ }
+
+ thread_ = std::make_unique<std::thread>([this]() { io_service_.run(); });
+ }
+
+ std::thread::id getThreadId() const {
+ if (thread_) {
+ return thread_->get_id();
+ } else {
+ throw errors::RuntimeException("Event thread is not running.");
+ }
+ }
+
+ template <typename Func>
+ void add(Func&& f) {
+ // If the function f
+ // TODO USe post in mac os, asio->post in xenial
+ io_service_.post(std::forward<Func&&>(f));
+ }
+
+ template <typename Func>
+ void tryRunHandlerNow(Func&& f) {
+ io_service_.dispatch(std::forward<Func&&>(f));
+ }
+
+ void stop() {
+ TRANSPORT_LOGI("Stopping event thread!");
+
+ io_service_.stop();
+
+ if (thread_ && thread_->joinable()) {
+ thread_->join();
+ }
+
+ thread_.reset();
+ }
+
+ bool stopped() { return io_service_.stopped(); }
+
+ asio::io_service& getIoService() { return io_service_; }
+
+ private:
+ std::unique_ptr<asio::io_service> internal_io_service_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ std::unique_ptr<std::thread> thread_;
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h
new file mode 100755
index 000000000..3ed4590bc
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h
@@ -0,0 +1,127 @@
+/*
+ * 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/errors/runtime_exception.h>
+#include <hicn/transport/utils/deadline_timer.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/log.h>
+
+#include <chrono>
+#include <cstddef>
+
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+namespace utils {
+
+class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> {
+ public:
+ explicit FdDeadlineTimer(EpollEventReactor &reactor)
+ : reactor_(reactor),
+ timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
+ flags_(0) {
+ if (timer_fd_ == -1) {
+ throw errors::RuntimeException("Impossible to create the timer!");
+ }
+ }
+
+ ~FdDeadlineTimer() { close(timer_fd_); }
+
+ template <typename WaitHandler>
+ void asyncWaitImpl(WaitHandler &&callback) {
+ // ASIO_WAIT_HANDLER_CHECK(WaitHandler, callback) type_check;
+
+ if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) {
+ throw errors::RuntimeException("Impossible to set the timer!");
+ }
+
+ uint32_t events = EPOLLIN;
+
+ reactor_.addFileDescriptor(
+ timer_fd_, events,
+ [callback{move(callback)}](const Event &event) -> int {
+ uint64_t s = 0;
+ std::error_code ec;
+
+ if (read(event.data.fd, &s, sizeof(s)) == -1) {
+ TRANSPORT_LOGE("Read error!!");
+ }
+
+ if (!(event.events & EPOLLIN)) {
+ ec = std::make_error_code(std::errc::operation_canceled);
+ }
+
+ callback(ec);
+
+ return 0;
+ });
+ }
+
+ void waitImpl() {
+ if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) {
+ throw errors::RuntimeException("Impossible to set the timer!");
+ }
+
+ uint64_t ret;
+
+ if (read(timer_fd_, &ret, sizeof(ret)) == -1) {
+ throw errors::RuntimeException(
+ "Error while waiting for the timer expiration.");
+ }
+ }
+
+ template <typename T, typename R>
+ void expiresFromNowImpl(std::chrono::duration<T, R> &&duration) {
+ std::memset(&new_value_, 0, sizeof(new_value_));
+ new_value_.it_value = std::chrono::duration_cast<struct timespec>(
+ std::forward<std::chrono::duration<T, R>>(duration));
+ }
+
+ template <typename TimePoint,
+ typename = std::enable_if_t<
+ std::is_same<std::remove_reference_t<TimePoint>,
+ std::chrono::steady_clock::time_point>::value,
+ TimePoint>>
+ void expiresAtImpl(TimePoint &&time_point) {
+ std::memset(&new_value_, 0, sizeof(new_value_));
+
+ new_value_.it_value = std::chrono::duration_cast<struct timespec>(
+ time_point.time_since_epoch());
+ flags_ |= TFD_TIMER_ABSTIME;
+ }
+
+ void cancelImpl() {
+ std::memset(&new_value_, 0, sizeof(new_value_));
+
+ if (timerfd_settime(timer_fd_, 0, &new_value_, NULL) == -1) {
+ throw errors::RuntimeException("Impossible to cancel the timer!");
+ }
+
+ // reactor_.delFileDescriptor(timer_fd_);
+ }
+
+ EventReactor &getEventReactor() { return reactor_; }
+
+ private:
+ EpollEventReactor &reactor_;
+ int timer_fd_;
+ EventCallback callback_;
+ struct itimerspec new_value_;
+ int flags_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/hash.h b/libtransport/src/hicn/transport/utils/hash.h
new file mode 100755
index 000000000..6815ca4bf
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/hash.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * 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 <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace utils {
+
+namespace hash {
+
+/*
+ * Fowler / Noll / Vo (FNV) Hash
+ * http://www.isthe.com/chongo/tech/comp/fnv/
+ */
+
+const uint32_t FNV_32_HASH_START = 2166136261UL;
+const uint64_t FNV_64_HASH_START = 14695981039346656037ULL;
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s,
+ uint32_t hash = FNV_32_HASH_START) {
+ for (; *s; ++s) {
+ hash +=
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+ hash ^= *s;
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n,
+ uint32_t hash = FNV_32_HASH_START) {
+ // forcing signed char, since other platforms can use unsigned
+ const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+ for (size_t i = 0; i < n; ++i) {
+ hash +=
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+ hash ^= char_buf[i];
+ }
+
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str,
+ uint32_t hash = FNV_32_HASH_START) {
+ return fnv32_buf(str.data(), str.size(), hash);
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s,
+ uint64_t hash = FNV_64_HASH_START) {
+ for (; *s; ++s) {
+ hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+ (hash << 8) + (hash << 40);
+ hash ^= *s;
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n,
+ uint64_t hash = FNV_64_HASH_START) {
+ // forcing signed char, since other platforms can use unsigned
+ const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+ for (size_t i = 0; i < n; ++i) {
+ hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+ (hash << 8) + (hash << 40);
+ hash ^= char_buf[i];
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str,
+ uint64_t hash = FNV_64_HASH_START) {
+ return fnv64_buf(str.data(), str.size(), hash);
+}
+
+} // namespace hash
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/identity.cc b/libtransport/src/hicn/transport/utils/identity.cc
new file mode 100755
index 000000000..bdf7f29f9
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/identity.cc
@@ -0,0 +1,130 @@
+/*
+ * 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/utils/identity.h>
+
+extern "C" {
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+}
+
+namespace utils {
+
+Identity::Identity(const std::string &keystore_name,
+ const std::string &keystore_password, CryptoSuite suite,
+ unsigned int key_length, unsigned int validity_days,
+ const std::string &subject_name) {
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(
+ keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(),
+ parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)),
+ key_length, validity_days);
+
+ parcAssertTrue(success,
+ "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.",
+ keystore_name.c_str(), keystore_password.c_str(),
+ subject_name.c_str(), static_cast<int>(key_length), validity_days);
+
+ PARCIdentityFile *identity_file =
+ parcIdentityFile_Create(keystore_name.c_str(), keystore_password.c_str());
+
+ identity_ =
+ parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(
+ identity_,
+ parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite)));
+
+ signer_ = std::make_shared<Signer>(signer);
+
+ signature_length_ = parcSigner_GetSignatureSize(signer);
+
+ parcSigner_Release(&signer);
+ parcIdentityFile_Release(&identity_file);
+}
+
+Identity::Identity(const Identity &other)
+ : signer_(other.signer_),
+ hash_algorithm_(other.hash_algorithm_),
+ signature_length_(other.signature_length_) {
+ parcSecurity_Init();
+ identity_ = parcIdentity_Acquire(other.identity_);
+}
+
+Identity Identity::generateIdentity(const std::string &subject_name) {
+ std::string keystore_name = "keystore";
+ std::string keystore_password = "password";
+ std::size_t key_length = 1024;
+ unsigned int validity_days = 30;
+ CryptoSuite suite = CryptoSuite::RSA_SHA256;
+
+ return utils::Identity(keystore_name, keystore_password, suite, key_length,
+ validity_days, subject_name);
+}
+
+Identity::Identity(std::string &file_name, std::string &password,
+ transport::core::HashAlgorithm hash_algorithm)
+ : hash_algorithm_(hash_algorithm) {
+ parcSecurity_Init();
+
+ PARCIdentityFile *identity_file =
+ parcIdentityFile_Create(file_name.c_str(), password.c_str());
+
+ identity_ =
+ parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(
+ identity_, static_cast<PARCCryptoHashType>(hash_algorithm));
+
+ signer_ = std::make_shared<Signer>(signer);
+
+ signature_length_ = parcSigner_GetSignatureSize(signer);
+
+ parcSigner_Release(&signer);
+ parcIdentityFile_Release(&identity_file);
+}
+
+// Identity::Identity(Identity &&other) {
+// identity_ = parcIdentity_Acquire(other.identity_);
+//}
+
+// Identity& Identity::operator=(const Identity& other) {
+// signer_ = other.signer_;
+// hash_algorithm_ = other.hash_algorithm_;
+// signature_length_ = other.signature_length_;
+// identity_ = parcIdentity_Acquire(other.identity_);
+
+// parcSecurity_Init();
+// }
+
+Identity::~Identity() {
+ parcIdentity_Release(&identity_);
+ parcSecurity_Fini();
+}
+
+std::string Identity::getFileName() {
+ return std::string(parcIdentity_GetFileName(identity_));
+}
+
+std::string Identity::getPassword() {
+ return std::string(parcIdentity_GetPassWord(identity_));
+}
+
+Signer &Identity::getSigner() { return *signer_; }
+
+unsigned int Identity::getSignatureLength() const { return signature_length_; }
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/identity.h b/libtransport/src/hicn/transport/utils/identity.h
new file mode 100755
index 000000000..018842ee3
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/identity.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/core/manifest_format.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/signer.h>
+
+extern "C" {
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+};
+
+#include <string>
+
+namespace utils {
+
+class Identity {
+ public:
+ Identity(const std::string &keystore_name,
+ const std::string &keystore_password, CryptoSuite suite,
+ unsigned int signature_length, unsigned int validity_days,
+ const std::string &subject_name);
+
+ // No copies
+ Identity(const Identity &other);
+
+ Identity(std::string &file_name, std::string &password,
+ transport::core::HashAlgorithm hash_algorithm);
+
+ ~Identity();
+
+ static Identity generateIdentity(const std::string &subject_name);
+
+ std::string getFileName();
+
+ std::string getPassword();
+
+ Signer &getSigner();
+
+ unsigned int getSignatureLength() const;
+
+ private:
+ PARCIdentity *identity_;
+ std::shared_ptr<Signer> signer_;
+ transport::core::HashAlgorithm hash_algorithm_;
+ unsigned int signature_length_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/key_id.h b/libtransport/src/hicn/transport/utils/key_id.h
new file mode 100755
index 000000000..d67b73d7a
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/key_id.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <cstdint>
+#include <utility>
+
+namespace utils {
+
+using KeyId = std::pair<uint8_t*, uint8_t>;
+
+}
diff --git a/libtransport/src/hicn/transport/utils/linux.h b/libtransport/src/hicn/transport/utils/linux.h
new file mode 100755
index 000000000..5820528e1
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/linux.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
+
+#ifdef __linux__
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <string>
+
+#define LINK_LOCAL_PREFIX 0xfe80
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress(
+ const std::string &interface_name, struct sockaddr_in6 *address) {
+ struct ifaddrs *ifap, *ifa;
+ char addr[INET6_ADDRSTRLEN];
+
+ getifaddrs(&ifap);
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ strcmp(ifa->ifa_name, interface_name.c_str()) == 0) {
+ struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr;
+ uint16_t prefix = 0;
+ memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t));
+
+ if (htons(LINK_LOCAL_PREFIX) != prefix) {
+ *address = *(struct sockaddr_in6 *)ifa->ifa_addr;
+ getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
+ sizeof(addr), NULL, 0, NI_NUMERICHOST);
+ TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr);
+ }
+ }
+ }
+
+ freeifaddrs(ifap);
+
+ return 0;
+}
+
+} // namespace utils
+
+#endif // __linux__ \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/literals.h b/libtransport/src/hicn/transport/utils/literals.h
new file mode 100755
index 000000000..bd00e0a58
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/literals.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <cstdint>
+
+TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) {
+ return static_cast<std::uint8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16(
+ unsigned long long value) {
+ return static_cast<std::uint16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32(
+ unsigned long long value) {
+ return static_cast<std::uint32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64(
+ unsigned long long value) {
+ return static_cast<std::uint64_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) {
+ return static_cast<std::int8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) {
+ return static_cast<std::int16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) {
+ return static_cast<std::int32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) {
+ return static_cast<std::int64_t>(value);
+} \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/log.cc b/libtransport/src/hicn/transport/utils/log.cc
new file mode 100755
index 000000000..064625ec0
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/log.cc
@@ -0,0 +1,1405 @@
+/*
+ * 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.
+ */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 wonder-mice
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* When defined, Android log (android/log.h) will be used by default instead of
+ * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
+ * will be provided by Android log. Android log features will be used to output
+ * log level and tag.
+ */
+#ifdef TRANSPORT_LOG_USE_ANDROID_LOG
+#undef TRANSPORT_LOG_USE_ANDROID_LOG
+#if defined(__ANDROID__)
+#define TRANSPORT_LOG_USE_ANDROID_LOG 1
+#else
+#define TRANSPORT_LOG_USE_ANDROID_LOG 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_ANDROID_LOG 0
+#endif
+/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
+ * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
+ * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
+ * non-public CFLog() function. Both use Apple System Log internally, but it's
+ * easier to call CFLog() from C than NSLog(). Current implementation doesn't
+ * support "%@" format specifier.
+ */
+#ifdef TRANSPORT_LOG_USE_NSLOG
+#undef TRANSPORT_LOG_USE_NSLOG
+#if defined(__APPLE__) && defined(__MACH__)
+#define TRANSPORT_LOG_USE_NSLOG 1
+#else
+#define TRANSPORT_LOG_USE_NSLOG 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_NSLOG 0
+#endif
+/* When defined, OutputDebugString() will be used instead of stderr (ignored on
+ * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
+ * UTF-8 data.
+ */
+#ifdef TRANSPORT_LOG_USE_DEBUGSTRING
+#undef TRANSPORT_LOG_USE_DEBUGSTRING
+#if defined(_WIN32) || defined(_WIN64)
+#define TRANSPORT_LOG_USE_DEBUGSTRING 1
+#else
+#define TRANSPORT_LOG_USE_DEBUGSTRING 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_DEBUGSTRING 0
+#endif
+/* When defined, TRANSPORT_LOG library will not contain definition of tag prefix
+ * variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX macro, for example:
+ *
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_TAG_PREFIX
+#undef TRANSPORT_LOG_EXTERN_TAG_PREFIX
+#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 1
+#else
+#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 0
+#endif
+/* When defined, TRANSPORT_LOG library will not contain definition of global
+ * format variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
+ *
+ * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 0
+#endif
+/* When defined, transport_log library will not contain definition of global
+ * output variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
+ *
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD,
+ * custom_output_callback};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 0
+#endif
+/* When defined, transport_log library will not contain definition of global
+ * output level variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
+ *
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = TRANSPORT_LOG_WARN;
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
+#endif
+/* When defined, implementation will prefer smaller code size over speed.
+ * Very rough estimate is that code will be up to 2x smaller and up to 2x
+ * slower. Disabled by default.
+ */
+#ifdef TRANSPORT_LOG_OPTIMIZE_SIZE
+#undef TRANSPORT_LOG_OPTIMIZE_SIZE
+#define TRANSPORT_LOG_OPTIMIZE_SIZE 1
+#else
+#define TRANSPORT_LOG_OPTIMIZE_SIZE 0
+#endif
+/* Size of the log line buffer. The buffer is allocated on stack. It limits
+ * maximum length of a log line.
+ */
+#ifndef TRANSPORT_LOG_BUF_SZ
+#define TRANSPORT_LOG_BUF_SZ 512
+#endif
+/* Default number of bytes in one line of memory output. For large values
+ * TRANSPORT_LOG_BUF_SZ also must be increased.
+ */
+#ifndef TRANSPORT_LOG_MEM_WIDTH
+#define TRANSPORT_LOG_MEM_WIDTH 32
+#endif
+/* String to put in the end of each log line (can be empty). Its value used by
+ * stderr output callback. Its size used as a default value for
+ * TRANSPORT_LOG_EOL_SZ.
+ */
+#ifndef TRANSPORT_LOG_EOL
+#define TRANSPORT_LOG_EOL "\n"
+#endif
+/* Default delimiter that separates parts of log message. Can NOT contain '%'
+ * or '\0'.
+ *
+ * Log message format specifications can override (or ignore) this value. For
+ * more details see TRANSPORT_LOG_MESSAGE_CTX_FORMAT,
+ * TRANSPORT_LOG_MESSAGE_SRC_FORMAT and TRANSPORT_LOG_MESSAGE_TAG_FORMAT.
+ */
+#ifndef TRANSPORT_LOG_DEF_DELIMITER
+#define TRANSPORT_LOG_DEF_DELIMITER " "
+#endif
+/* Specifies log message context format. Log message context includes date,
+ * time, process id, thread id and message's log level. Custom information can
+ * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
+ * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * Must be defined as a tuple, for example:
+ *
+ * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY,
+ * S(" > "))
+ *
+ * In that case, resulting log message will be:
+ *
+ * 2016.12.22 > TAG function@filename.c:line Message text
+ *
+ * Note, that tag, source location and message text are not impacted by
+ * this setting. See TRANSPORT_LOG_MESSAGE_TAG_FORMAT and
+ * TRANSPORT_LOG_MESSAGE_SRC_FORMAT.
+ *
+ * If message context must be visually separated from the rest of the message,
+ * it must be reflected in context format (notice trailing S(" > ") in the
+ * example above).
+ *
+ * S(str) adds constant string str. String can NOT contain '%' or '\0'.
+ *
+ * F_INIT(statements) adds initialization statement(s) that will be evaluated
+ * once for each log message. All statements are evaluated in specified order.
+ * Several F_INIT() fields can be used in every log message format
+ * specification. Fields, like F_UINT(width, value), are allowed to use results
+ * of initialization statements. If statement introduces variables (or other
+ * names, like structures) they must be prefixed with "f_". Statements must be
+ * enclosed into additional "()". Example:
+ *
+ * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \
+ * (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
+ * YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ * F_UINT(5, f_ru.ru_nsignals), \
+ * S(" "))
+ *
+ * F_UINT(width, value) adds unsigned integer value extended with up to width
+ * spaces (for alignment purposes). Value can be any expression that evaluates
+ * to unsigned integer. If expression contains non-standard functions, they
+ * must be declared with F_INIT(). Example:
+ *
+ * #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \
+ * (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ * F_INIT(( unsigned tickcount(); )), \
+ * F_UINT(5, tickcount()), \
+ * S(" "))
+ *
+ * Other log message format specifications follow same rules, but have a
+ * different set of supported fields.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_CTX_FORMAT
+#define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \
+ (MONTH, S("-"), DAY, S(TRANSPORT_LOG_DEF_DELIMITER), HOUR, S(":"), MINUTE, \
+ S(":"), SECOND, S("."), MILLISECOND, S(TRANSPORT_LOG_DEF_DELIMITER), PID, \
+ S(TRANSPORT_LOG_DEF_DELIMITER), TID, S(TRANSPORT_LOG_DEF_DELIMITER), LEVEL, \
+ S(TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Example:
+ */
+/* Specifies log message tag format. It includes tag prefix and tag. Custom
+ * information can be added as well. Supported fields:
+ * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
+ *
+ * PREFIX<prefix_delimiter>TAG<tag_delimiter>
+ *
+ * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
+ * will be used only when prefixed tag is not empty. Example:
+ *
+ * #define TRANSPORT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
+ *
+ * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_TAG_FORMAT
+#define TRANSPORT_LOG_MESSAGE_TAG_FORMAT (TAG(".", TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Specifies log message source location format. It includes function name,
+ * file name and file line. Custom information can be added as well. Supported
+ * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_SRC_FORMAT
+#define TRANSPORT_LOG_MESSAGE_SRC_FORMAT \
+ (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Fields that can be used in log message format specifications (see above).
+ * Mentioning them here explicitly, so we know that nobody else defined them
+ * before us. See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#define YEAR YEAR
+#define MONTH MONTH
+#define DAY DAY
+#define MINUTE MINUTE
+#define SECOND SECOND
+#define MILLISECOND MILLISECOND
+#define PID PID
+#define TID TID
+#define LEVEL LEVEL
+#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
+#define FUNCTION FUNCTION
+#define FILENAME FILENAME
+#define FILELINE FILELINE
+#define S(str) S(str)
+#define F_INIT(statements) F_INIT(statements)
+#define F_UINT(width, value) F_UINT(width, value)
+/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
+ * Must be larger than or equal to length of TRANSPORT_LOG_EOL with terminating
+ * null.
+ */
+#ifndef TRANSPORT_LOG_EOL_SZ
+#define TRANSPORT_LOG_EOL_SZ sizeof(TRANSPORT_LOG_EOL)
+#endif
+/* Compile instrumented version of the library to facilitate unit testing.
+ */
+#ifndef TRANSPORT_LOG_INSTRUMENTED
+#define TRANSPORT_LOG_INSTRUMENTED 0
+#endif
+
+#if defined(__linux__)
+#if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#endif
+#if defined(__MINGW32__)
+#ifdef __STRICT_ANSI__
+#undef __STRICT_ANSI__
+#endif
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <hicn/transport/utils/log.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#if defined(__linux__)
+#include <linux/limits.h>
+#else
+#include <sys/syslimits.h>
+#endif
+#endif
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+#include <sys/types.h>
+#if !defined(__ANDROID__)
+#include <sys/syscall.h>
+#endif
+#endif
+#if defined(__MACH__)
+#include <pthread.h>
+#endif
+
+#define INLINE _TRANSPORT_LOG_INLINE
+#define VAR_UNUSED(var) (void)var
+#define RETVAL_UNUSED(expr) \
+ do { \
+ while (expr) break; \
+ } while (0)
+#define STATIC_ASSERT(name, cond) typedef char assert_##name[(cond) ? 1 : -1]
+#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
+#ifndef _countof
+#define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
+#endif
+
+#if TRANSPORT_LOG_INSTRUMENTED
+#define INSTRUMENTED_CONST
+#else
+#define INSTRUMENTED_CONST const
+#endif
+
+#define _PP_PASTE_2(a, b) a##b
+#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
+
+#define _PP_PASTE_3(a, b, c) a##b##c
+#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
+
+/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
+ * as a single token and requires additional expansion to realize that it's
+ * actually a list. If not for it, there would be no need in this extra
+ * expansion.
+ */
+#define _PP_ID(x) x
+#define _PP_NARGS_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
+ _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, \
+ _24, ...) \
+ _24
+#define _PP_NARGS(...) \
+ _PP_ID(_PP_NARGS_N(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \
+ 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+
+/* There is a more efficient way to implement this, but it requires
+ * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
+ * have one.
+ */
+#define _PP_HEAD__(x, ...) x
+#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
+#define _PP_HEAD(xs) _PP_HEAD_ xs
+#define _PP_TAIL_(x, ...) (__VA_ARGS__)
+#define _PP_TAIL(xs) _PP_TAIL_ xs
+#define _PP_UNTUPLE_(...) __VA_ARGS__
+#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
+
+/* Apply function macro to each element in tuple. Output is not
+ * enforced to be a tuple.
+ */
+#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
+#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
+#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
+#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
+#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
+#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
+#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
+#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
+#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
+#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
+#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
+#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
+#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
+#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
+#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
+#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
+#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
+#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
+#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
+#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
+#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
+#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
+#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
+#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs)(f, xs)
+
+/* Apply function macro to each element in tuple in reverse order.
+ * Output is not enforced to be a tuple.
+ */
+#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs)(f, xs)
+
+/* Used to implement _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All
+ * possible fields must be mentioned here. Not counting F_INIT() here because
+ * it's somewhat special and is handled spearatly (at least for now).
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__ (0 << 0)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__YEAR (1 << 1)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MONTH (1 << 2)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__DAY (1 << 3)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__HOUR (1 << 4)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1 << 5)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__SECOND (1 << 6)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1 << 7)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__PID (1 << 8)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TID (1 << 9)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1 << 10)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1 << 11)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1 << 12)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1 << 13)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1 << 14)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__S(s) (1 << 15)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0 << 16)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1 << 17)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_MASK_, _, field)
+
+/* Logical "or" of masks of fields used in specified format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format) \
+ (0 _PP_MAP(| _TRANSPORT_LOG_MESSAGE_FORMAT_MASK, format))
+
+/* Expands to expressions that evaluates to true if field is used in
+ * specified format specification. Example:
+ *
+ * #if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT,
+ * TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ * ...
+ * #endif
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
+ (_TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) & \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format))
+
+/* Same, but checks all supported format specifications.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \
+ (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \
+ TRANSPORT_LOG_MESSAGE_TAG_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, \
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT))
+
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED \
+ (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT))
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \
+ aggregate initializer */
+#define memccpy _memccpy
+#endif
+
+#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)
+#define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
+static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap) {
+ const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);
+ return 0 < n ? n : (int)sz + 1; /* no need in _vscprintf() for now */
+}
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+#define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
+static int fake_snprintf(char *s, size_t sz, const char *fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ const int n = fake_vsnprintf(s, sz, fmt, va);
+ va_end(va);
+ return n;
+}
+#endif
+#endif
+
+typedef void (*time_cb)(struct tm *const tm, unsigned *const usec);
+typedef void (*pid_cb)(int *const pid, int *const tid);
+typedef void (*buffer_cb)(transport_log_message *msg, char *buf);
+
+typedef struct src_location {
+ const char *const func;
+ const char *const file;
+ const unsigned line;
+} src_location;
+
+typedef struct mem_block {
+ const void *const d;
+ const unsigned d_sz;
+} mem_block;
+
+static void time_callback(struct tm *const tm, unsigned *const usec);
+static void pid_callback(int *const pid, int *const tid);
+static void buffer_callback(transport_log_message *msg, char *buf);
+
+STATIC_ASSERT(eol_fits_eol_sz,
+ sizeof(TRANSPORT_LOG_EOL) <= TRANSPORT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_greater_than_zero, 0 < TRANSPORT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_less_than_buf_sz,
+ TRANSPORT_LOG_EOL_SZ < TRANSPORT_LOG_BUF_SZ);
+#if !defined(_WIN32) && !defined(_WIN64)
+STATIC_ASSERT(buf_sz_less_than_pipe_buf, TRANSPORT_LOG_BUF_SZ <= PIPE_BUF);
+#endif
+static const char c_hex[] = "0123456789abcdef";
+
+static INSTRUMENTED_CONST unsigned g_buf_sz =
+ TRANSPORT_LOG_BUF_SZ - TRANSPORT_LOG_EOL_SZ;
+static INSTRUMENTED_CONST time_cb g_time_cb = time_callback;
+static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;
+static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;
+
+#if TRANSPORT_LOG_USE_ANDROID_LOG
+#include <android/log.h>
+
+static INLINE int android_lvl(const int lvl) {
+ switch (lvl) {
+ case TRANSPORT_LOG_VERBOSE:
+ return ANDROID_LOG_VERBOSE;
+ case TRANSPORT_LOG_DEBUG:
+ return ANDROID_LOG_DEBUG;
+ case TRANSPORT_LOG_INFO:
+ return ANDROID_LOG_INFO;
+ case TRANSPORT_LOG_WARN:
+ return ANDROID_LOG_WARN;
+ case TRANSPORT_LOG_ERROR:
+ return ANDROID_LOG_ERROR;
+ case TRANSPORT_LOG_FATAL:
+ return ANDROID_LOG_FATAL;
+ default:
+ ASSERT_UNREACHABLE("Bad log level");
+ return ANDROID_LOG_UNKNOWN;
+ }
+}
+
+static void out_android_callback(const transport_log_message *const msg,
+ void *arg) {
+ VAR_UNUSED(arg);
+ *msg->p = 0;
+ const char *tag = msg->p;
+ if (msg->tag_e != msg->tag_b) {
+ tag = msg->tag_b;
+ *msg->tag_e = 0;
+ }
+ __android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);
+}
+
+enum { OUT_ANDROID_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX };
+#define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
+#endif
+
+#if TRANSPORT_LOG_USE_NSLOG
+#include <CoreFoundation/CoreFoundation.h>
+CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);
+
+static INLINE int apple_lvl(const int lvl) {
+ switch (lvl) {
+ case TRANSPORT_LOG_VERBOSE:
+ return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */
+ ;
+ case TRANSPORT_LOG_DEBUG:
+ return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */
+ ;
+ case TRANSPORT_LOG_INFO:
+ return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */
+ ;
+ case TRANSPORT_LOG_WARN:
+ return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */
+ ;
+ case TRANSPORT_LOG_ERROR:
+ return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */
+ ;
+ case TRANSPORT_LOG_FATAL:
+ return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */
+ ;
+ default:
+ ASSERT_UNREACHABLE("Bad log level");
+ return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */
+ ;
+ }
+}
+
+static void out_nslog_callback(const transport_log_message *const msg,
+ void *arg) {
+ VAR_UNUSED(arg);
+ *msg->p = 0;
+ CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b);
+}
+
+enum { OUT_NSLOG_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX };
+#define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
+#endif
+
+#if TRANSPORT_LOG_USE_DEBUGSTRING
+#include <windows.h>
+
+static void out_debugstring_callback(const transport_log_message *const msg,
+ void *arg) {
+ VAR_UNUSED(arg);
+ msg->p[0] = '\n';
+ msg->p[1] = '\0';
+ OutputDebugStringA(msg->buf);
+}
+
+enum { OUT_DEBUGSTRING_MASK = TRANSPORT_LOG_PUT_STD };
+#define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
+#endif
+
+void transport_log_out_stderr_callback(const transport_log_message *const msg,
+ void *arg) {
+ VAR_UNUSED(arg);
+ const size_t eol_len = sizeof(TRANSPORT_LOG_EOL) - 1;
+ memcpy(msg->p, TRANSPORT_LOG_EOL, eol_len);
+#if defined(_WIN32) || defined(_WIN64)
+ /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
+ without FILE_WRITE_DATA */
+ DWORD written;
+ WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,
+ (DWORD)(msg->p - msg->buf + eol_len), &written, 0);
+#else
+ /* write() is atomic for buffers less than or equal to PIPE_BUF. */
+ RETVAL_UNUSED(
+ write(STDERR_FILENO, msg->buf, (size_t)(msg->p - msg->buf) + eol_len));
+#endif
+}
+
+static const transport_log_output out_stderr = {TRANSPORT_LOG_OUT_STDERR};
+
+#if !TRANSPORT_LOG_EXTERN_TAG_PREFIX
+TRANSPORT_LOG_DEFINE_TAG_PREFIX = 0;
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {TRANSPORT_LOG_MEM_WIDTH};
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#if TRANSPORT_LOG_USE_ANDROID_LOG
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};
+#elif TRANSPORT_LOG_USE_NSLOG
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};
+#elif TRANSPORT_LOG_USE_DEBUGSTRING
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};
+#else
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR};
+#endif
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;
+#endif
+
+const transport_log_spec _transport_log_stderr_spec = {
+ TRANSPORT_LOG_GLOBAL_FORMAT,
+ &out_stderr,
+};
+
+static const transport_log_spec global_spec = {
+ TRANSPORT_LOG_GLOBAL_FORMAT,
+ TRANSPORT_LOG_GLOBAL_OUTPUT,
+};
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+static char lvl_char(const int lvl) {
+ switch (lvl) {
+ case TRANSPORT_LOG_VERBOSE:
+ return 'V';
+ case TRANSPORT_LOG_DEBUG:
+ return 'D';
+ case TRANSPORT_LOG_INFO:
+ return 'I';
+ case TRANSPORT_LOG_WARN:
+ return 'W';
+ case TRANSPORT_LOG_ERROR:
+ return 'E';
+ case TRANSPORT_LOG_FATAL:
+ return 'F';
+ default:
+ ASSERT_UNREACHABLE("Bad log level");
+ return '?';
+ }
+}
+#endif
+
+#define GCCVER_LESS(MAJOR, MINOR, PATCH) \
+ (__GNUC__ < MAJOR || (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \
+ (__GNUC_MINOR__ == MINOR && \
+ __GNUC_PATCHLEVEL__ < PATCH))))
+
+#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4, 7, 0)
+#define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
+#define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
+#define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
+#define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
+#define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
+/* Note: will not store old value of *vp in *ep (non-standard behaviour) */
+#define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
+ __sync_bool_compare_and_swap(vp, *(ep), d)
+#endif
+
+#if !TRANSPORT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
+#define TCACHE
+#define TCACHE_STALE (0x40000000)
+#define TCACHE_FLUID (0x40000000 | 0x80000000)
+static unsigned g_tcache_mode = TCACHE_STALE;
+static struct timeval g_tcache_tv = {0, 0};
+static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static INLINE int tcache_get(const struct timeval *const tv,
+ struct tm *const tm) {
+ unsigned mode;
+ mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);
+ if (0 == (mode & TCACHE_FLUID)) {
+ mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);
+ if (0 == (mode & TCACHE_FLUID)) {
+ if (g_tcache_tv.tv_sec == tv->tv_sec) {
+ *tm = g_tcache_tm;
+ __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+ return !0;
+ }
+ __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);
+ }
+ __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+ }
+ return 0;
+}
+
+static INLINE void tcache_set(const struct timeval *const tv,
+ struct tm *const tm) {
+ unsigned stale = TCACHE_STALE;
+ if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID, 0,
+ __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
+ g_tcache_tv = *tv;
+ g_tcache_tm = *tm;
+ __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);
+ }
+}
+#endif
+
+static void time_callback(struct tm *const tm, unsigned *const msec) {
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED
+ VAR_UNUSED(tm);
+ VAR_UNUSED(msec);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ tm->tm_year = st.wYear;
+ tm->tm_mon = st.wMonth - 1;
+ tm->tm_mday = st.wDay;
+ tm->tm_wday = st.wDayOfWeek;
+ tm->tm_hour = st.wHour;
+ tm->tm_min = st.wMinute;
+ tm->tm_sec = st.wSecond;
+ *msec = st.wMilliseconds;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+#ifndef TCACHE
+ localtime_r(&tv.tv_sec, tm);
+#else
+ if (!tcache_get(&tv, tm)) {
+ localtime_r(&tv.tv_sec, tm);
+ tcache_set(&tv, tm);
+ }
+#endif
+ *msec = (unsigned)tv.tv_usec / 1000;
+#endif
+#endif
+}
+
+static void pid_callback(int *const pid, int *const tid) {
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(PID, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ VAR_UNUSED(pid);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+ *pid = GetCurrentProcessId();
+#else
+ *pid = getpid();
+#endif
+#endif
+
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ VAR_UNUSED(tid);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+ *tid = GetCurrentThreadId();
+#elif defined(__ANDROID__)
+ *tid = gettid();
+#elif defined(__linux__)
+ *tid = syscall(SYS_gettid);
+#elif defined(__MACH__)
+ *tid = (int)pthread_mach_thread_np(pthread_self());
+#else
+#define Platform not supported
+#endif
+#endif
+}
+
+static void buffer_callback(transport_log_message *msg, char *buf) {
+ msg->e = (msg->p = msg->buf = buf) + g_buf_sz;
+}
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, \
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+static const char *funcname(const char *func) { return func ? func : ""; }
+#endif
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, \
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+static const char *filename(const char *file) {
+ const char *f = file;
+ for (const char *p = file; 0 != *p; ++p) {
+ if ('/' == *p || '\\' == *p) {
+ f = p + 1;
+ }
+ }
+ return f;
+}
+#endif
+
+static INLINE size_t nprintf_size(transport_log_message *const msg) {
+ // *nprintf() always puts 0 in the end when input buffer is not empty. This
+ // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
+ // leaves space for one more character. Some put_xxx() functions don't use
+ // *nprintf() and could use that last character. In that case log line will
+ // have multiple (two) half-written parts which is confusing. To workaround
+ // that we allow *nprintf() to write its 0 in the eol area (which is always
+ // not empty).
+ return (size_t)(msg->e - msg->p + 1);
+}
+
+static INLINE void put_nprintf(transport_log_message *const msg, const int n) {
+ if (0 < n) {
+ msg->p = n < msg->e - msg->p ? msg->p + n : msg->e;
+ }
+}
+
+static INLINE char *put_padding_r(const unsigned w, const char wc, char *p,
+ char *e) {
+ for (char *const b = e - w; b < p; *--p = wc) {
+ }
+ return p;
+}
+
+static char *put_integer_r(unsigned v, const int sign, const unsigned w,
+ const char wc, char *const e) {
+ static const char _signs[] = {'-', '0', '+'};
+ static const char *const signs = _signs + 1;
+ char *p = e;
+ do {
+ *--p = '0' + v % 10;
+ } while (0 != (v /= 10));
+ if (0 == sign) return put_padding_r(w, wc, p, e);
+ if ('0' != wc) {
+ *--p = signs[sign];
+ return put_padding_r(w, wc, p, e);
+ }
+ p = put_padding_r(w, wc, p, e + 1);
+ *--p = signs[sign];
+ return p;
+}
+
+static INLINE char *put_uint_r(const unsigned v, const unsigned w,
+ const char wc, char *const e) {
+ return put_integer_r(v, 0, w, wc, e);
+}
+
+static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
+ char *const e) {
+ return 0 <= v ? put_integer_r((unsigned)v, 0, w, wc, e)
+ : put_integer_r((unsigned)-v, -1, w, wc, e);
+}
+
+static INLINE char *put_stringn(const char *const s_p, const char *const s_e,
+ char *const p, char *const e) {
+ const ptrdiff_t m = e - p;
+ ptrdiff_t n = s_e - s_p;
+ if (n > m) {
+ n = m;
+ }
+ memcpy(p, s_p, n);
+ return p + n;
+}
+
+static INLINE char *put_string(const char *s, char *p, char *const e) {
+ const ptrdiff_t n = e - p;
+ char *const c = (char *)memccpy(p, s, '\0', n);
+ return 0 != c ? c - 1 : e;
+}
+
+static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
+ char *const p, char *const e) {
+ char buf[16];
+ char *const se = buf + _countof(buf);
+ char *sp = put_uint_r(v, w, wc, se);
+ return put_stringn(sp, se, p, e);
+}
+
+#define PUT_CSTR_R(p, STR) \
+ do { \
+ for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
+ *--(p) = (STR)[i]; \
+ } \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+#define PUT_CSTR_CHECKED(p, e, STR) \
+ do { \
+ for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
+ *(p)++ = (STR)[i]; \
+ } \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+/* F_INIT field support.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__YEAR
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MONTH
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__DAY
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__HOUR
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MINUTE
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__SECOND
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__PID
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TID
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__LEVEL
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILENAME
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILELINE
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__S(s)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT_, _, field)
+
+/* Implements generation of printf-like format string for log message
+ * format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ ""
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
+
+/* Implements generation of printf-like format parameters for log message
+ * format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR \
+ , (unsigned)(tm.tm_year + 1900)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH \
+ , (unsigned)(tm.tm_mon + 1)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY , (unsigned)tm.tm_mday
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR , (unsigned)tm.tm_hour
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE , (unsigned)tm.tm_min
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND , (unsigned)tm.tm_sec
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND , (unsigned)msec
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID , pid
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID , tid
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL \
+ , (char)lvl_char(msg->lvl)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION , funcname(src->func)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME , filename(src->file)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE , src->line
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) , v
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
+
+/* Implements generation of put_xxx_t statements for log message specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__YEAR \
+ p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MONTH \
+ p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__DAY \
+ p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__HOUR \
+ p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE \
+ p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__SECOND \
+ p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND \
+ p = put_uint_r(msec, 3, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) \
+ p = put_uint_r(v, w, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
+
+static void put_ctx(transport_log_message *const msg) {
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ VAR_UNUSED(msg);
+#else
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED
+ struct tm tm;
+ unsigned msec;
+ g_time_cb(&tm, &msec);
+#endif
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \
+ PID, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+ _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ int pid, tid;
+ g_pid_cb(&pid, &tid);
+#endif
+
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+ int n;
+ n = snprintf(msg->p, nprintf_size(msg),
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT,
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL,
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT));
+ put_nprintf(msg, n);
+#else
+ char buf[64];
+ char *const e = buf + sizeof(buf);
+ char *p = e;
+ _PP_RMAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R,
+ TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ msg->p = put_stringn(p, e, msg->p, msg->e);
+#endif
+#endif
+}
+
+#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \
+ do { \
+ const char *ch; \
+ msg->tag_b = msg->p; \
+ if (0 != (ch = _transport_log_tag_prefix)) { \
+ for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \
+ } \
+ } \
+ if (0 != (ch = tag) && 0 != tag[0]) { \
+ if (msg->tag_b != msg->p) { \
+ PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \
+ } \
+ for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \
+ } \
+ } \
+ msg->tag_e = msg->p; \
+ if (msg->tag_b != msg->p) { \
+ PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \
+ } \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+/* Implements simple put statements for log message specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) \
+ PUT_TAG(msg, tag, pd, td);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FUNCTION \
+ msg->p = put_string(funcname(src->func), msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILENAME \
+ msg->p = put_string(filename(src->file), msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILELINE \
+ msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__S(s) \
+ PUT_CSTR_CHECKED(msg->p, msg->e, s);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) \
+ msg->p = put_uint(v, w, ' ', msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT(field) \
+ _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_, _, field)
+
+static void put_tag(transport_log_message *const msg, const char *const tag) {
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, \
+ TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+ VAR_UNUSED(tag);
+#endif
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+ VAR_UNUSED(msg);
+#else
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+#endif
+}
+
+static void put_src(transport_log_message *const msg,
+ const src_location *const src) {
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \
+ FUNCTION, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \
+ !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS( \
+ FILENAME, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \
+ !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, \
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+ VAR_UNUSED(src);
+#endif
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+ VAR_UNUSED(msg);
+#else
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+ int n;
+ n = snprintf(msg->p, nprintf_size(msg),
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT,
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL,
+ TRANSPORT_LOG_MESSAGE_SRC_FORMAT));
+ put_nprintf(msg, n);
+#else
+ _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+#endif
+#endif
+}
+
+static void put_msg(transport_log_message *const msg, const char *const fmt,
+ va_list va) {
+ int n;
+ msg->msg_b = msg->p;
+ n = vsnprintf(msg->p, nprintf_size(msg), fmt, va);
+ put_nprintf(msg, n);
+}
+
+static void output_mem(const transport_log_spec *log,
+ transport_log_message *const msg,
+ const mem_block *const mem) {
+ if (0 == mem->d || 0 == mem->d_sz) {
+ return;
+ }
+ const unsigned char *mem_p = (const unsigned char *)mem->d;
+ const unsigned char *const mem_e = mem_p + mem->d_sz;
+ const unsigned char *mem_cut;
+ const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;
+ char *const hex_b = msg->msg_b;
+ char *const ascii_b = hex_b + 2 * mem_width + 2;
+ char *const ascii_e = ascii_b + mem_width;
+ if (msg->e < ascii_e) {
+ return;
+ }
+ while (mem_p != mem_e) {
+ char *hex = hex_b;
+ char *ascii = ascii_b;
+ for (mem_cut = mem_width < mem_e - mem_p ? mem_p + mem_width : mem_e;
+ mem_cut != mem_p; ++mem_p) {
+ const unsigned char ch = *mem_p;
+ *hex++ = c_hex[(0xf0 & ch) >> 4];
+ *hex++ = c_hex[(0x0f & ch)];
+ *ascii++ = isprint(ch) ? (char)ch : '?';
+ }
+ while (hex != ascii_b) {
+ *hex++ = ' ';
+ }
+ msg->p = ascii;
+ log->output->callback(msg, log->output->arg);
+ }
+}
+
+void transport_log_set_tag_prefix(const char *const prefix) {
+ _transport_log_tag_prefix = prefix;
+}
+
+void transport_log_set_mem_width(const unsigned w) {
+ _transport_log_global_format.mem_width = w;
+}
+
+void transport_log_set_output_level(const int lvl) {
+ _transport_log_global_output_lvl = lvl;
+}
+
+void transport_log_set_output_v(const unsigned mask, void *const arg,
+ const transport_log_output_cb callback) {
+ _transport_log_global_output.mask = mask;
+ _transport_log_global_output.arg = arg;
+ _transport_log_global_output.callback = callback;
+}
+
+static void _transport_log_write_imp(const transport_log_spec *log,
+ const src_location *const src,
+ const mem_block *const mem, const int lvl,
+ const char *const tag,
+ const char *const fmt, va_list va) {
+ transport_log_message msg;
+ char buf[TRANSPORT_LOG_BUF_SZ];
+ const unsigned mask = log->output->mask;
+ msg.lvl = lvl;
+ msg.tag = tag;
+ g_buffer_cb(&msg, buf);
+ if (TRANSPORT_LOG_PUT_CTX & mask) {
+ put_ctx(&msg);
+ }
+ if (TRANSPORT_LOG_PUT_TAG & mask) {
+ put_tag(&msg, tag);
+ }
+ if (0 != src && TRANSPORT_LOG_PUT_SRC & mask) {
+ put_src(&msg, src);
+ }
+ if (TRANSPORT_LOG_PUT_MSG & mask) {
+ put_msg(&msg, fmt, va);
+ }
+ log->output->callback(&msg, log->output->arg);
+ if (0 != mem && TRANSPORT_LOG_PUT_MSG & mask) {
+ output_mem(log, &msg, mem);
+ }
+}
+
+void _transport_log_write_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const char *const fmt, ...) {
+ const src_location src = {func, file, line};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_aux_d(const char *const func, const char *const file,
+ const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...) {
+ const src_location src = {func, file, line};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(log, &src, 0, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write(const int lvl, const char *const tag,
+ const char *const fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(log, 0, 0, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_mem_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const void *const d,
+ const unsigned d_sz, const char *const fmt,
+ ...) {
+ const src_location src = {func, file, line};
+ const mem_block mem = {d, d_sz};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_mem_aux_d(const char *const func,
+ const char *const file, const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...) {
+ const src_location src = {func, file, line};
+ const mem_block mem = {d, d_sz};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_mem(const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...) {
+ const mem_block mem = {d, d_sz};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);
+ va_end(va);
+}
+
+void _transport_log_write_mem_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...) {
+ const mem_block mem = {d, d_sz};
+ va_list va;
+ va_start(va, fmt);
+ _transport_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);
+ va_end(va);
+} \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/log.h b/libtransport/src/hicn/transport/utils/log.h
new file mode 100755
index 000000000..17e47e7df
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/log.h
@@ -0,0 +1,1057 @@
+/*
+ * 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.
+ */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 wonder-mice
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+/* To detect incompatible changes you can define TRANSPORT_LOG_VERSION_REQUIRED
+ * to be the current value of TRANSPORT_LOG_VERSION before including this file
+ * (or via compiler command line):
+ *
+ * #define TRANSPORT_LOG_VERSION_REQUIRED 4
+ * #include <hicn/transport_log.h>
+ *
+ * Compilation will fail when included file has different version.
+ */
+#define TRANSPORT_LOG_VERSION 4
+#if defined(TRANSPORT_LOG_VERSION_REQUIRED)
+#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION
+#error different transport_log version required
+#endif
+#endif
+
+/* Log level guideline:
+ * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely
+ * unexpected. Process can't continue and must be terminated. Example: division
+ * by zero, unexpected modifications from other thread.
+ * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected.
+ * The process is able to recover and continue execution. Example: out of memory
+ * (could also be FATAL if not handled properly).
+ * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen
+ * and significantly changes application behavior for some period of time.
+ * Example: configuration file not found, auth error.
+ * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state
+ * transition.
+ * Example: app started, user logged in.
+ * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct
+ * the execution path. Usually disabled in release builds.
+ * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release
+ * builds.
+ *
+ * *Ideally*, log file of debugged, well tested, production ready application
+ * should be empty or very small. Choosing a right log level is as important as
+ * providing short and self descriptive log message.
+ */
+#define TRANSPORT_LOG_VERBOSE 1
+#define TRANSPORT_LOG_DEBUG 2
+#define TRANSPORT_LOG_INFO 3
+#define TRANSPORT_LOG_WARN 4
+#define TRANSPORT_LOG_ERROR 5
+#define TRANSPORT_LOG_FATAL 6
+#define TRANSPORT_LOG_NONE 0xFF
+
+/* "Current" log level is a compile time check and has no runtime overhead. Log
+ * level that is below current log level it said to be "disabled". Otherwise,
+ * it's "enabled". Log messages that are disabled has no runtime overhead - they
+ * are converted to no-op by preprocessor and then eliminated by compiler.
+ * Current log level is configured per compilation module (.c/.cpp/.m file) by
+ * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL
+ * has higer priority and when defined overrides value provided by
+ * TRANSPORT_LOG_DEF_LEVEL.
+ *
+ * Common practice is to define default current log level with
+ * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp,
+ * etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO
+ *
+ * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then
+ * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and
+ * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL
+#elif defined(TRANSPORT_LOG_DEF_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO
+#else
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG
+#endif
+#endif
+
+/* "Output" log level is a runtime check. When log level is below output log
+ * level it said to be "turned off" (or just "off" for short). Otherwise it's
+ * "turned on" (or just "on"). Log levels that were "disabled" (see
+ * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but
+ * "enabled" log levels could be "turned off". Only messages with log level
+ * which is "turned on" will reach output facility. All other messages will be
+ * ignored (and their arguments will not be evaluated). Output log level is a
+ * global property and configured per process using
+ * transport_log_set_output_level() function which can be called at any time.
+ *
+ * Though in some cases it could be useful to configure output log level per
+ * compilation module or per library. There are two ways to achieve that:
+ * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired
+ * output log level.
+ * - Copy transport_log.h and transport_log.c files into your library and build
+ * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See
+ * TRANSPORT_LOG_LIBRARY_PREFIX for more details.
+ *
+ * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that
+ * corresponds to desired output log level. Use it only when compilation module
+ * is required to have output log level which is different from global output
+ * log level set by transport_log_set_output_level() function. For other cases,
+ * consider defining TRANSPORT_LOG_LEVEL or using
+ * transport_log_set_output_level() function.
+ *
+ * Example:
+ *
+ * #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level
+ * #include <hicn/transport_log.h>
+ * static int g_module_log_level = TRANSPORT_LOG_INFO;
+ * static void foo() {
+ * TRANSPORT_LOGI("Will check g_module_log_level for output log level");
+ * }
+ * void debug_log(bool on) {
+ * g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO;
+ * }
+ *
+ * Note on performance. This expression will be evaluated each time message is
+ * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL
+ * for details). Keep this expression as simple as possible, otherwise it will
+ * not only add runtime overhead, but also will increase size of call site
+ * (which will result in larger executable). The prefered way is to use integer
+ * variable (as in example above). If structure must be used, log_level field
+ * must be the first field in this structure:
+ *
+ * #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level)
+ * #include <hicn/transport_log.h>
+ * struct config {
+ * int log_level;
+ * unsigned other_field;
+ * [...]
+ * };
+ * static config g_config = {TRANSPORT_LOG_INFO, 0, ...};
+ *
+ * This allows compiler to generate more compact load instruction (no need to
+ * specify offset since it's zero). Calling a function to get output log level
+ * is generaly a bad idea, since it will increase call site size and runtime
+ * overhead even further.
+ */
+#if defined(TRANSPORT_LOG_OUTPUT_LEVEL)
+#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL
+#else
+#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl
+#endif
+
+/* "Tag" is a compound string that could be associated with a log message. It
+ * consists of tag prefix and tag (both are optional).
+ *
+ * Tag prefix is a global property and configured per process using
+ * transport_log_set_tag_prefix() function. Tag prefix identifies context in
+ * which component or module is running (e.g. process name). For example, the
+ * same library could be used in both client and server processes that work on
+ * the same machine. Tag prefix could be used to easily distinguish between
+ * them. For more details about tag prefix see transport_log_set_tag_prefix()
+ * function. Tag prefix
+ *
+ * Tag identifies component or module. It is configured per compilation module
+ * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG.
+ * TRANSPORT_LOG_TAG has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to
+ * (const char *), so for strings double quotes must be used.
+ *
+ * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g.
+ * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\"
+ *
+ * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_TAG "MAIN"
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will
+ * be added to the log message (tag prefix still could be added though).
+ *
+ * Output example:
+ *
+ * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1
+ * | |
+ * | +- tag (e.g. module)
+ * +- tag prefix (e.g. process name)
+ */
+#if defined(TRANSPORT_LOG_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG
+#elif defined(TRANSPORT_LOG_DEF_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG
+#else
+#define _TRANSPORT_LOG_TAG 0
+#endif
+
+/* Source location is part of a log line that describes location (function or
+ * method name, file name and line number, e.g. "runloop@main.cpp:68") of a
+ * log statement that produced it.
+ * Source location formats are:
+ * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line.
+ * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and
+ * line number, e.g. "@main.cpp:68").
+ * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or
+ * method name, file and line number, e.g. "runloop@main.cpp:68").
+ */
+#define TRANSPORT_LOG_SRCLOC_NONE 0
+#define TRANSPORT_LOG_SRCLOC_SHORT 1
+#define TRANSPORT_LOG_SRCLOC_LONG 2
+
+/* Source location format is configured per compilation module (.c/.cpp/.m
+ * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC.
+ * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_SRCLOC.
+ *
+ * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in
+ * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG
+ *
+ * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then
+ * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined)
+ * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC
+#elif defined(TRANSPORT_LOG_DEF_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+#else
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG
+#endif
+#endif
+#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION
+#else
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0
+#endif
+
+/* Censoring provides conditional logging of secret information, also known as
+ * Personally Identifiable Information (PII) or Sensitive Personal Information
+ * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled
+ * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked
+ * as "secrets" will be ignored and will have zero overhead (arguments also will
+ * not be evaluated).
+ */
+#define TRANSPORT_LOG_CENSORED 1
+#define TRANSPORT_LOG_UNCENSORED 0
+
+/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
+ * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING.
+ * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_CENSORING.
+ *
+ * Common practice is to define default censoring with
+ * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt,
+ * gyp, etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED
+ *
+ * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m
+ * files before including transport_log.h (consider doing it only for debug
+ * purposes and be very careful not to push such temporary changes to source
+ * control):
+ *
+ * #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are
+ * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds
+ * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not
+ * defined).
+ */
+#if defined(TRANSPORT_LOG_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING
+#elif defined(TRANSPORT_LOG_DEF_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED
+#else
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+#endif
+#endif
+
+/* Check censoring at compile time. Evaluates to true when censoring is disabled
+ * (i.e. when secrets will be logged). For example:
+ *
+ * #if TRANSPORT_LOG_SECRETS
+ * char ssn[16];
+ * getSocialSecurityNumber(ssn);
+ * TRANSPORT_LOGI("Customer ssn: %s", ssn);
+ * #endif
+ *
+ * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single
+ * log statement.
+ */
+#define TRANSPORT_LOG_SECRETS \
+ (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING)
+
+/* Static (compile-time) initialization support allows to configure logging
+ * before entering main() function. This mostly useful in C++ where functions
+ * and methods could be called during initialization of global objects. Those
+ * functions and methods could record log messages too and for that reason
+ * static initialization of logging configuration is customizable.
+ *
+ * Macros below allow to specify values to use for initial configuration:
+ * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
+ * TRANSPORT_LOG_MEM_WIDTH in transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default:
+ * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in
+ * transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level
+ * (default: 0 - all levals are "turned on")
+ *
+ * For example, in log_config.c:
+ *
+ * #include <hicn/transport_log.h>
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp";
+ * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD,
+ * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL =
+ * TRANSPORT_LOG_INFO;
+ *
+ * However, to use any of those macros transport_log library must be compiled
+ * with following macros defined:
+ * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define
+ * TRANSPORT_LOG_EXTERN_TAG_PREFIX
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+ *
+ * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX
+ * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used
+ * exactly once somewhere. Otherwise build will fail with link error (undefined
+ * symbol).
+ */
+#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix
+#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \
+ transport_log_format _transport_log_global_format
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \
+ transport_log_output _transport_log_global_output
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \
+ int _transport_log_global_output_lvl
+
+/* Pointer to global format options. Direct modification is not allowed. Use
+ * transport_log_set_mem_width() instead. Could be used to initialize
+ * transport_log_spec structure:
+ *
+ * const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD,
+ * output_callback, 0}; const transport_log_spec g_spec =
+ * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec,
+ * "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_FORMAT \
+ ((const transport_log_format *)&_transport_log_global_format)
+
+/* Pointer to global output variable. Direct modification is not allowed. Use
+ * transport_log_set_output_v() or transport_log_set_output_p() instead. Could
+ * be used to initialize transport_log_spec structure:
+ *
+ * const transport_log_format g_format = {40};
+ * const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT};
+ * TRANSPORT_LOGI_AUX(&g_spec, "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_OUTPUT \
+ ((const transport_log_output *)&_transport_log_global_output)
+
+/* When defined, all library symbols produced by linker will be prefixed with
+ * provided value. That allows to use transport_log library privately in another
+ * libraries without exposing transport_log symbols in their original form (to
+ * avoid possible conflicts with other libraries / components that also could
+ * use transport_log for logging). Value must be without quotes, for example:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_
+ *
+ * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when
+ * building transport_log library AND it also must be defined to the same value
+ * when building a library that uses it. For example, consider fictional
+ * KittyHttp library that wants to use transport_log for logging. First approach
+ * that could be taken is to add transport_log.h and transport_log.c to the
+ * KittyHttp's source code tree directly. In that case it will be enough just to
+ * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script:
+ *
+ * // KittyHttp/CMakeLists.txt
+ * target_compile_definitions(KittyHttp PRIVATE
+ * "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_")
+ *
+ * If KittyHttp doesn't want to include transport_log source code in its source
+ * tree and wants to build transport_log as a separate library than
+ * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined
+ * to KittyHttp_ AND KittyHttp library itself also needs to define
+ * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build
+ * script, as in example above, or by providing a wrapper header that KittyHttp
+ * library will need to use instead of transport_log.h:
+ *
+ * // KittyHttpLogging.h
+ * #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_
+ * #include <hicn/transport_log.h>
+ *
+ * Regardless of the method chosen, the end result is that transport_log symbols
+ * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say
+ * DogeBrowser) also uses transport_log for logging, they will not interferer
+ * with each other. Both will have their own log level, output facility, format
+ * options etc.
+ */
+#ifdef TRANSPORT_LOG_LIBRARY_PREFIX
+#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name
+#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name)
+#define _TRANSPORT_LOG_DECOR(name) \
+ _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name)
+
+#define transport_log_set_tag_prefix \
+ _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix)
+#define transport_log_set_mem_width \
+ _TRANSPORT_LOG_DECOR(transport_log_set_mem_width)
+#define transport_log_set_output_level \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_level)
+#define transport_log_set_output_v \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_v)
+#define transport_log_set_output_p \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_p)
+#define transport_log_out_stderr_callback \
+ _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback)
+#define _transport_log_tag_prefix \
+ _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix)
+#define _transport_log_global_format \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_format)
+#define _transport_log_global_output \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_output)
+#define _transport_log_global_output_lvl \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl)
+#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d)
+#define _transport_log_write_aux_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d)
+#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write)
+#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux)
+#define _transport_log_write_mem_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d)
+#define _transport_log_write_mem_aux_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d)
+#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem)
+#define _transport_log_write_mem_aux \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux)
+#define _transport_log_stderr_spec \
+ _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec)
+#endif
+
+#if defined(__printflike)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __printflike(str_index, first_to_check)
+#elif defined(__GNUC__)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __attribute__((format(__printf__, str_index, first_to_check)))
+#else
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check)
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
+#define _TRANSPORT_LOG_FUNCTION __FUNCTION__
+#else
+#define _TRANSPORT_LOG_FUNCTION __func__
+#endif
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#define _TRANSPORT_LOG_INLINE __inline
+#define _TRANSPORT_LOG_IF(cond) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \
+ __pragma(warning(pop))
+#define _TRANSPORT_LOG_WHILE(cond) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \
+ __pragma(warning(pop))
+#else
+#define _TRANSPORT_LOG_INLINE inline
+#define _TRANSPORT_LOG_IF(cond) if (cond)
+#define _TRANSPORT_LOG_WHILE(cond) while (cond)
+#endif
+#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0)
+#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
+ * Use 0 or empty string to disable (default). Common use is to set it to
+ * the process (or build target) name (e.g. to separate client and server
+ * processes). Function will NOT copy provided prefix string, but will store the
+ * pointer. Hence specified prefix string must remain valid. See
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main()
+ * function. See TRANSPORT_LOG_TAG for more information about tag and tag
+ * prefix.
+ */
+void transport_log_set_tag_prefix(const char *const prefix);
+
+/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
+ *
+ * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo
+ * |<- w bytes ->| |<- w chars ->|
+ *
+ * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details.
+ */
+void transport_log_set_mem_width(const unsigned w);
+
+/* Set "output" log level. See TRANSPORT_LOG_LEVEL and
+ * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels.
+ */
+void transport_log_set_output_level(const int lvl);
+
+/* Put mask is a set of flags that define what fields will be added to each
+ * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be
+ * used to alter its behavior. See transport_log_set_output_v() for more
+ * details.
+ *
+ * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds
+ * (NDEBUG is not defined).
+ */
+enum {
+ TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
+ TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
+ TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
+ TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
+ TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */
+};
+
+typedef struct transport_log_message {
+ int lvl; /* Log level of the message */
+ const char *tag; /* Associated tag (without tag prefix) */
+ char *buf; /* Buffer start */
+ char *e; /* Buffer end (last position where EOL with 0 could be written) */
+ char *p; /* Buffer content end (append position) */
+ char *tag_b; /* Prefixed tag start */
+ char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
+ char *msg_b; /* Message start (expanded format string) */
+} transport_log_message;
+
+/* Type of output callback function. It will be called for each log line allowed
+ * by both "current" and "output" log levels ("enabled" and "turned on").
+ * Callback function is allowed to modify content of the buffers pointed by the
+ * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
+ * is UTF-8 encoded (no BOM mark).
+ */
+typedef void (*transport_log_output_cb)(const transport_log_message *msg,
+ void *arg);
+
+/* Format options. For more details see transport_log_set_mem_width().
+ */
+typedef struct transport_log_format {
+ unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
+} transport_log_format;
+
+/* Output facility.
+ */
+typedef struct transport_log_output {
+ unsigned
+ mask; /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */
+ void *arg; /* User provided output callback argument */
+ transport_log_output_cb callback; /* Output callback function */
+} transport_log_output;
+
+/* Set output callback function.
+ *
+ * Mask allows to control what information will be added to the log line buffer
+ * before callback function is invoked. Default mask value is
+ * TRANSPORT_LOG_PUT_STD.
+ */
+void transport_log_set_output_v(const unsigned mask, void *const arg,
+ const transport_log_output_cb callback);
+static _TRANSPORT_LOG_INLINE void transport_log_set_output_p(
+ const transport_log_output *const output) {
+ transport_log_set_output_v(output->mask, output->arg, output->callback);
+}
+
+/* Used with _AUX macros and allows to override global format and output
+ * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for
+ * values from global configuration. Example:
+ *
+ * static const transport_log_output module_output = {
+ * TRANSPORT_LOG_PUT_STD, 0, custom_output_callback
+ * };
+ * static const transport_log_spec module_spec = {
+ * TRANSPORT_LOG_GLOBAL_FORMAT, &module_output
+ * };
+ * TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
+ *
+ * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details.
+ */
+typedef struct transport_log_spec {
+ const transport_log_format *format;
+ const transport_log_output *output;
+} transport_log_spec;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Execute log statement if condition is true. Example:
+ *
+ * TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this"));
+ * TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this"));
+ *
+ * Keep in mind though, that if condition can't be evaluated at compile time,
+ * then it will be evaluated at run time. This will increase exectuable size
+ * and can have noticeable performance overhead. Try to limit conditions to
+ * expressions that can be evaluated at compile time.
+ */
+#define TRANSPORT_LOG_IF(cond, f) \
+ do { \
+ _TRANSPORT_LOG_IF((cond)) { f; } \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+/* Mark log statement as "secret". Log statements that are marked as secrets
+ * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED).
+ * Example:
+ *
+ * TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card));
+ * TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher
+ * bytes:"));
+ */
+#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f)
+
+/* Check "current" log level at compile time (ignoring "output" log level).
+ * Evaluates to true when specified log level is enabled. For example:
+ *
+ * #if TRANSPORT_LOG_ENABLED_DEBUG
+ * const char *const g_enum_strings[] = {
+ * "enum_value_0", "enum_value_1", "enum_value_2"
+ * };
+ * #endif
+ * // ...
+ * #if TRANSPORT_LOG_ENABLED_DEBUG
+ * TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]);
+ * #endif
+ *
+ * See TRANSPORT_LOG_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL)
+#define TRANSPORT_LOG_ENABLED_VERBOSE \
+ TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL)
+
+/* Check "output" log level at run time (taking into account "current" log
+ * level as well). Evaluates to true when specified log level is turned on AND
+ * enabled. For example:
+ *
+ * if (TRANSPORT_LOG_ON_DEBUG)
+ * {
+ * char hash[65];
+ * sha256(data_ptr, data_sz, hash);
+ * TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash);
+ * }
+ *
+ * See TRANSPORT_LOG_OUTPUT_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ON(lvl) \
+ (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL)
+#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *_transport_log_tag_prefix;
+extern transport_log_format _transport_log_global_format;
+extern transport_log_output _transport_log_global_output;
+extern int _transport_log_global_output_lvl;
+extern const transport_log_spec _transport_log_stderr_spec;
+
+void _transport_log_write_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+void _transport_log_write_aux_d(const char *const func, const char *const file,
+ const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(7, 8);
+void _transport_log_write(const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(3, 4);
+void _transport_log_write_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(4, 5);
+void _transport_log_write_mem_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const void *const d,
+ const unsigned d_sz, const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(8, 9);
+void _transport_log_write_mem_aux_d(const char *const func,
+ const char *const file, const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(9, 10);
+void _transport_log_write_mem(const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(5, 6);
+void _transport_log_write_mem_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Message logging macros:
+ * - TRANSPORT_LOGV("format string", args, ...)
+ * - TRANSPORT_LOGD("format string", args, ...)
+ * - TRANSPORT_LOGI("format string", args, ...)
+ * - TRANSPORT_LOGW("format string", args, ...)
+ * - TRANSPORT_LOGE("format string", args, ...)
+ * - TRANSPORT_LOGF("format string", args, ...)
+ *
+ * Memory logging macros:
+ * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
+ *
+ * Auxiliary logging macros:
+ * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...)
+ *
+ * Auxiliary memory logging macros:
+ * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ *
+ * Preformatted string logging macros:
+ * - TRANSPORT_LOGV_STR("preformatted string");
+ * - TRANSPORT_LOGD_STR("preformatted string");
+ * - TRANSPORT_LOGI_STR("preformatted string");
+ * - TRANSPORT_LOGW_STR("preformatted string");
+ * - TRANSPORT_LOGE_STR("preformatted string");
+ * - TRANSPORT_LOGF_STR("preformatted string");
+ *
+ * Explicit log level and tag macros:
+ * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...)
+ * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args,
+ * ...)
+ * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
+ * "format string", args, ...)
+ *
+ * Format string follows printf() conventions. Both data_ptr and data_sz could
+ * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
+ * match format specifiers in format string.
+ *
+ * Library assuming UTF-8 encoding for all strings (char *), including format
+ * string itself.
+ */
+#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#else
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, log, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, log, lvl, tag, d, d_sz, \
+ __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#endif
+
+static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) {
+ (void)dummy;
+}
+
+#define _TRANSPORT_LOG_UNUSED(...) \
+ do { \
+ _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+#if TRANSPORT_LOG_ENABLED_VERBOSE
+#define TRANSPORT_LOGV(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_DEBUG
+#define TRANSPORT_LOGD(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_INFO
+#define TRANSPORT_LOGI(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_WARN
+#define TRANSPORT_LOGW(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_ERROR
+#define TRANSPORT_LOGE(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_FATAL
+#define TRANSPORT_LOGF(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s))
+#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s))
+#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s))
+#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s))
+#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s))
+#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Output to standard error stream. Library uses it by default, though in few
+ * cases it could be necessary to specify it explicitly. For example, when
+ * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT,
+ * application must define and initialize global output variable:
+ *
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR};
+ *
+ * Another example is when using custom output, stderr could be used as a
+ * fallback when custom output facility failed to initialize:
+ *
+ * transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR);
+ */
+enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD };
+void transport_log_out_stderr_callback(const transport_log_message *const msg,
+ void *arg);
+#define TRANSPORT_LOG_OUT_STDERR \
+ TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback
+
+/* Predefined spec for stderr. Uses global format options
+ * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to
+ * force output to stderr for a particular message. Example:
+ *
+ * f = fopen("foo.log", "w");
+ * if (!f)
+ * TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file");
+ */
+#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec)
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/membuf.cc b/libtransport/src/hicn/transport/utils/membuf.cc
new file mode 100755
index 000000000..0ab1a6044
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/membuf.cc
@@ -0,0 +1,864 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2013-present Facebook, Inc.
+ * 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.
+ */
+
+/*
+ * The code in this file if adapated from the IOBuf of folly:
+ * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h
+ */
+
+#include <hicn/transport/utils/membuf.h>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <stdexcept>
+#include <vector>
+
+using std::unique_ptr;
+
+namespace {
+
+enum : uint16_t {
+ kHeapMagic = 0xa5a5,
+ // This memory segment contains an MemBuf that is still in use
+ kMemBufInUse = 0x01,
+ // This memory segment contains buffer data that is still in use
+ kDataInUse = 0x02,
+};
+
+enum : std::size_t {
+ // When create() is called for buffers less than kDefaultCombinedBufSize,
+ // we allocate a single combined memory segment for the MemBuf and the data
+ // together. See the comments for createCombined()/createSeparate() for more
+ // details.
+ //
+ // (The size of 1k is largely just a guess here. We could could probably do
+ // benchmarks of real applications to see if adjusting this number makes a
+ // difference. Callers that know their exact use case can also explicitly
+ // call createCombined() or createSeparate().)
+ kDefaultCombinedBufSize = 1024
+};
+
+// Helper function for MemBuf::takeOwnership()
+void takeOwnershipError(bool freeOnError, void* buf,
+ utils::MemBuf::FreeFunction freeFn, void* userData) {
+ if (!freeOnError) {
+ return;
+ }
+ if (!freeFn) {
+ free(buf);
+ return;
+ }
+ try {
+ freeFn(buf, userData);
+ } catch (...) {
+ // The user's free function is not allowed to throw.
+ // (We are already in the middle of throwing an exception, so
+ // we cannot let this exception go unhandled.)
+ abort();
+ }
+}
+
+} // namespace
+
+namespace utils {
+
+struct MemBuf::HeapPrefix {
+ explicit HeapPrefix(uint16_t flg) : magic(kHeapMagic), flags(flg) {}
+ ~HeapPrefix() {
+ // Reset magic to 0 on destruction. This is solely for debugging purposes
+ // to help catch bugs where someone tries to use HeapStorage after it has
+ // been deleted.
+ magic = 0;
+ }
+
+ uint16_t magic;
+ std::atomic<uint16_t> flags;
+};
+
+struct MemBuf::HeapStorage {
+ HeapPrefix prefix;
+ // The MemBuf is last in the HeapStorage object.
+ // This way operator new will work even if allocating a subclass of MemBuf
+ // that requires more space.
+ utils::MemBuf buf;
+};
+
+struct MemBuf::HeapFullStorage {
+ // Make sure jemalloc allocates from the 64-byte class. Putting this here
+ // because HeapStorage is private so it can't be at namespace level.
+ static_assert(sizeof(HeapStorage) <= 64,
+ "MemBuf may not grow over 56 bytes!");
+
+ HeapStorage hs;
+ SharedInfo shared;
+ std::max_align_t align;
+};
+
+MemBuf::SharedInfo::SharedInfo() : freeFn(nullptr), userData(nullptr) {
+ // Use relaxed memory ordering here. Since we are creating a new SharedInfo,
+ // no other threads should be referring to it yet.
+ refcount.store(1, std::memory_order_relaxed);
+}
+
+MemBuf::SharedInfo::SharedInfo(FreeFunction fn, void* arg)
+ : freeFn(fn), userData(arg) {
+ // Use relaxed memory ordering here. Since we are creating a new SharedInfo,
+ // no other threads should be referring to it yet.
+ refcount.store(1, std::memory_order_relaxed);
+}
+
+void* MemBuf::operator new(size_t size) {
+ size_t fullSize = offsetof(HeapStorage, buf) + size;
+ auto* storage = static_cast<HeapStorage*>(malloc(fullSize));
+
+ new (&storage->prefix) HeapPrefix(kMemBufInUse);
+ return &(storage->buf);
+}
+
+void* MemBuf::operator new(size_t /* size */, void* ptr) { return ptr; }
+
+void MemBuf::operator delete(void* ptr) {
+ auto* storageAddr = static_cast<uint8_t*>(ptr) - offsetof(HeapStorage, buf);
+ auto* storage = reinterpret_cast<HeapStorage*>(storageAddr);
+ releaseStorage(storage, kMemBufInUse);
+}
+
+void MemBuf::operator delete(void* /* ptr */, void* /* placement */) {
+ // Provide matching operator for `MemBuf::new` to avoid MSVC compilation
+ // warning (C4291) about memory leak when exception is thrown in the
+ // constructor.
+}
+
+void MemBuf::releaseStorage(HeapStorage* storage, uint16_t freeFlags) {
+ // Use relaxed memory order here. If we are unlucky and happen to get
+ // out-of-date data the compare_exchange_weak() call below will catch
+ // it and load new data with memory_order_acq_rel.
+ auto flags = storage->prefix.flags.load(std::memory_order_acquire);
+
+ while (true) {
+ uint16_t newFlags = uint16_t(flags & ~freeFlags);
+ if (newFlags == 0) {
+ // The storage space is now unused. Free it.
+ storage->prefix.HeapPrefix::~HeapPrefix();
+ free(storage);
+ return;
+ }
+
+ // This storage segment still contains portions that are in use.
+ // Just clear the flags specified in freeFlags for now.
+ auto ret = storage->prefix.flags.compare_exchange_weak(
+ flags, newFlags, std::memory_order_acq_rel);
+ if (ret) {
+ // We successfully updated the flags.
+ return;
+ }
+
+ // We failed to update the flags. Some other thread probably updated them
+ // and cleared some of the other bits. Continue around the loop to see if
+ // we are the last user now, or if we need to try updating the flags again.
+ }
+}
+
+void MemBuf::freeInternalBuf(void* /* buf */, void* userData) {
+ auto* storage = static_cast<HeapStorage*>(userData);
+ releaseStorage(storage, kDataInUse);
+}
+
+MemBuf::MemBuf(CreateOp, std::size_t capacity)
+ : next_(this),
+ prev_(this),
+ data_(nullptr),
+ length_(0),
+ flags_and_shared_info_(0) {
+ SharedInfo* info;
+ allocExtBuffer(capacity, &buf_, &info, &capacity_);
+ setSharedInfo(info);
+ data_ = buf_;
+}
+
+MemBuf::MemBuf(CopyBufferOp /* op */, const void* buf, std::size_t size,
+ std::size_t headroom, std::size_t min_tailroom)
+ : MemBuf(CREATE, headroom + size + min_tailroom) {
+ advance(headroom);
+ if (size > 0) {
+ assert(buf != nullptr);
+ memcpy(writableData(), buf, size);
+ append(size);
+ }
+}
+
+unique_ptr<MemBuf> MemBuf::create(std::size_t capacity) {
+ // For smaller-sized buffers, allocate the MemBuf, SharedInfo, and the buffer
+ // all with a single allocation.
+ //
+ // We don't do this for larger buffers since it can be wasteful if the user
+ // needs to reallocate the buffer but keeps using the same MemBuf object.
+ // In this case we can't free the data space until the MemBuf is also
+ // destroyed. Callers can explicitly call createCombined() or
+ // createSeparate() if they know their use case better, and know if they are
+ // likely to reallocate the buffer later.
+ if (capacity <= kDefaultCombinedBufSize) {
+ return createCombined(capacity);
+ }
+ return createSeparate(capacity);
+}
+
+unique_ptr<MemBuf> MemBuf::createCombined(std::size_t capacity) {
+ // To save a memory allocation, allocate space for the MemBuf object, the
+ // SharedInfo struct, and the data itself all with a single call to malloc().
+ size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity;
+ size_t mallocSize = requiredStorage;
+ auto* storage = static_cast<HeapFullStorage*>(malloc(mallocSize));
+
+ new (&storage->hs.prefix) HeapPrefix(kMemBufInUse | kDataInUse);
+ new (&storage->shared) SharedInfo(freeInternalBuf, storage);
+
+ uint8_t* bufAddr = reinterpret_cast<uint8_t*>(&storage->align);
+ uint8_t* storageEnd = reinterpret_cast<uint8_t*>(storage) + mallocSize;
+ size_t actualCapacity = size_t(storageEnd - bufAddr);
+ unique_ptr<MemBuf> ret(new (&storage->hs.buf) MemBuf(
+ InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared),
+ bufAddr, actualCapacity, bufAddr, 0));
+ return ret;
+}
+
+unique_ptr<MemBuf> MemBuf::createSeparate(std::size_t capacity) {
+ return std::make_unique<MemBuf>(CREATE, capacity);
+}
+
+unique_ptr<MemBuf> MemBuf::createChain(size_t totalCapacity,
+ std::size_t maxBufCapacity) {
+ unique_ptr<MemBuf> out =
+ create(std::min(totalCapacity, size_t(maxBufCapacity)));
+ size_t allocatedCapacity = out->capacity();
+
+ while (allocatedCapacity < totalCapacity) {
+ unique_ptr<MemBuf> newBuf = create(
+ std::min(totalCapacity - allocatedCapacity, size_t(maxBufCapacity)));
+ allocatedCapacity += newBuf->capacity();
+ out->prependChain(std::move(newBuf));
+ }
+
+ return out;
+}
+
+MemBuf::MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity,
+ std::size_t length, FreeFunction freeFn, void* userData,
+ bool freeOnError)
+ : next_(this),
+ prev_(this),
+ data_(static_cast<uint8_t*>(buf)),
+ buf_(static_cast<uint8_t*>(buf)),
+ length_(length),
+ capacity_(capacity),
+ flags_and_shared_info_(
+ packFlagsAndSharedInfo(flag_free_shared_info, nullptr)) {
+ try {
+ setSharedInfo(new SharedInfo(freeFn, userData));
+ } catch (...) {
+ takeOwnershipError(freeOnError, buf, freeFn, userData);
+ throw;
+ }
+}
+
+unique_ptr<MemBuf> MemBuf::takeOwnership(void* buf, std::size_t capacity,
+ std::size_t length,
+ FreeFunction freeFn, void* userData,
+ bool freeOnError) {
+ try {
+ // TODO: We could allocate the MemBuf object and SharedInfo all in a single
+ // memory allocation. We could use the existing HeapStorage class, and
+ // define a new kSharedInfoInUse flag. We could change our code to call
+ // releaseStorage(flag_free_shared_info) when this flag_free_shared_info,
+ // rather than directly calling delete.
+ //
+ // Note that we always pass freeOnError as false to the constructor.
+ // If the constructor throws we'll handle it below. (We have to handle
+ // allocation failures from std::make_unique too.)
+ return std::make_unique<MemBuf>(TAKE_OWNERSHIP, buf, capacity, length,
+ freeFn, userData, false);
+ } catch (...) {
+ takeOwnershipError(freeOnError, buf, freeFn, userData);
+ throw;
+ }
+}
+
+MemBuf::MemBuf(WrapBufferOp, const void* buf, std::size_t capacity) noexcept
+ : MemBuf(InternalConstructor(), 0,
+ // We cast away the const-ness of the buffer here.
+ // This is okay since MemBuf users must use unshare() to create a
+ // copy of this buffer before writing to the buffer.
+ static_cast<uint8_t*>(const_cast<void*>(buf)), capacity,
+ static_cast<uint8_t*>(const_cast<void*>(buf)), capacity) {}
+
+unique_ptr<MemBuf> MemBuf::wrapBuffer(const void* buf, std::size_t capacity) {
+ return std::make_unique<MemBuf>(WRAP_BUFFER, buf, capacity);
+}
+
+MemBuf MemBuf::wrapBufferAsValue(const void* buf,
+ std::size_t capacity) noexcept {
+ return MemBuf(WrapBufferOp::WRAP_BUFFER, buf, capacity);
+}
+
+MemBuf::MemBuf() noexcept {}
+
+MemBuf::MemBuf(MemBuf&& other) noexcept
+ : data_(other.data_),
+ buf_(other.buf_),
+ length_(other.length_),
+ capacity_(other.capacity_),
+ flags_and_shared_info_(other.flags_and_shared_info_) {
+ // Reset other so it is a clean state to be destroyed.
+ other.data_ = nullptr;
+ other.buf_ = nullptr;
+ other.length_ = 0;
+ other.capacity_ = 0;
+ other.flags_and_shared_info_ = 0;
+
+ // If other was part of the chain, assume ownership of the rest of its chain.
+ // (It's only valid to perform move assignment on the head of a chain.)
+ if (other.next_ != &other) {
+ next_ = other.next_;
+ next_->prev_ = this;
+ other.next_ = &other;
+
+ prev_ = other.prev_;
+ prev_->next_ = this;
+ other.prev_ = &other;
+ }
+}
+
+MemBuf::MemBuf(const MemBuf& other) { *this = other.cloneAsValue(); }
+
+MemBuf::MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
+ std::size_t capacity, uint8_t* data, std::size_t length) noexcept
+ : next_(this),
+ prev_(this),
+ data_(data),
+ buf_(buf),
+ length_(length),
+ capacity_(capacity),
+ flags_and_shared_info_(flagsAndSharedInfo) {
+ assert(data >= buf);
+ assert(data + length <= buf + capacity);
+}
+
+MemBuf::~MemBuf() {
+ // Destroying an MemBuf destroys the entire chain.
+ // Users of MemBuf should only explicitly delete the head of any chain.
+ // The other elements in the chain will be automatically destroyed.
+ while (next_ != this) {
+ // Since unlink() returns unique_ptr() and we don't store it,
+ // it will automatically delete the unlinked element.
+ (void)next_->unlink();
+ }
+
+ decrementRefcount();
+}
+
+MemBuf& MemBuf::operator=(MemBuf&& other) noexcept {
+ if (this == &other) {
+ return *this;
+ }
+
+ // If we are part of a chain, delete the rest of the chain.
+ while (next_ != this) {
+ // Since unlink() returns unique_ptr() and we don't store it,
+ // it will automatically delete the unlinked element.
+ (void)next_->unlink();
+ }
+
+ // Decrement our refcount on the current buffer
+ decrementRefcount();
+
+ // Take ownership of the other buffer's data
+ data_ = other.data_;
+ buf_ = other.buf_;
+ length_ = other.length_;
+ capacity_ = other.capacity_;
+ flags_and_shared_info_ = other.flags_and_shared_info_;
+ // Reset other so it is a clean state to be destroyed.
+ other.data_ = nullptr;
+ other.buf_ = nullptr;
+ other.length_ = 0;
+ other.capacity_ = 0;
+ other.flags_and_shared_info_ = 0;
+
+ // If other was part of the chain, assume ownership of the rest of its chain.
+ // (It's only valid to perform move assignment on the head of a chain.)
+ if (other.next_ != &other) {
+ next_ = other.next_;
+ next_->prev_ = this;
+ other.next_ = &other;
+
+ prev_ = other.prev_;
+ prev_->next_ = this;
+ other.prev_ = &other;
+ }
+
+ return *this;
+}
+
+MemBuf& MemBuf::operator=(const MemBuf& other) {
+ if (this != &other) {
+ *this = MemBuf(other);
+ }
+ return *this;
+}
+
+bool MemBuf::empty() const {
+ const MemBuf* current = this;
+ do {
+ if (current->length() != 0) {
+ return false;
+ }
+ current = current->next_;
+ } while (current != this);
+ return true;
+}
+
+size_t MemBuf::countChainElements() const {
+ size_t numElements = 1;
+ for (MemBuf* current = next_; current != this; current = current->next_) {
+ ++numElements;
+ }
+ return numElements;
+}
+
+std::size_t MemBuf::computeChainDataLength() const {
+ std::size_t fullLength = length_;
+ for (MemBuf* current = next_; current != this; current = current->next_) {
+ fullLength += current->length_;
+ }
+ return fullLength;
+}
+
+void MemBuf::prependChain(unique_ptr<MemBuf>&& iobuf) {
+ // Take ownership of the specified MemBuf
+ MemBuf* other = iobuf.release();
+
+ // Remember the pointer to the tail of the other chain
+ MemBuf* otherTail = other->prev_;
+
+ // Hook up prev_->next_ to point at the start of the other chain,
+ // and other->prev_ to point at prev_
+ prev_->next_ = other;
+ other->prev_ = prev_;
+
+ // Hook up otherTail->next_ to point at us,
+ // and prev_ to point back at otherTail,
+ otherTail->next_ = this;
+ prev_ = otherTail;
+}
+
+unique_ptr<MemBuf> MemBuf::clone() const {
+ return std::make_unique<MemBuf>(cloneAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneOne() const {
+ return std::make_unique<MemBuf>(cloneOneAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneCoalesced() const {
+ return std::make_unique<MemBuf>(cloneCoalescedAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneCoalescedWithHeadroomTailroom(
+ std::size_t new_headroom, std::size_t new_tailroom) const {
+ return std::make_unique<MemBuf>(
+ cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom));
+}
+
+MemBuf MemBuf::cloneAsValue() const {
+ auto tmp = cloneOneAsValue();
+
+ for (MemBuf* current = next_; current != this; current = current->next_) {
+ tmp.prependChain(current->cloneOne());
+ }
+
+ return tmp;
+}
+
+MemBuf MemBuf::cloneOneAsValue() const {
+ if (SharedInfo* info = sharedInfo()) {
+ setFlags(flag_maybe_shared);
+ info->refcount.fetch_add(1, std::memory_order_acq_rel);
+ }
+ return MemBuf(InternalConstructor(), flags_and_shared_info_, buf_, capacity_,
+ data_, length_);
+}
+
+MemBuf MemBuf::cloneCoalescedAsValue() const {
+ const std::size_t new_headroom = headroom();
+ const std::size_t new_tailroom = prev()->tailroom();
+ return cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom);
+}
+
+MemBuf MemBuf::cloneCoalescedAsValueWithHeadroomTailroom(
+ std::size_t new_headroom, std::size_t new_tailroom) const {
+ if (!isChained()) {
+ return cloneOneAsValue();
+ }
+ // Coalesce into newBuf
+ const std::size_t new_length = computeChainDataLength();
+ const std::size_t new_capacity = new_length + new_headroom + new_tailroom;
+ MemBuf newBuf{CREATE, new_capacity};
+ newBuf.advance(new_headroom);
+
+ auto current = this;
+ do {
+ if (current->length() > 0) {
+ memcpy(newBuf.writableTail(), current->data(), current->length());
+ newBuf.append(current->length());
+ }
+ current = current->next();
+ } while (current != this);
+
+ return newBuf;
+}
+
+void MemBuf::unshareOneSlow() {
+ // Allocate a new buffer for the data
+ uint8_t* buf;
+ SharedInfo* sharedInfo;
+ std::size_t actualCapacity;
+ allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity);
+
+ // Copy the data
+ // Maintain the same amount of headroom. Since we maintained the same
+ // minimum capacity we also maintain at least the same amount of tailroom.
+ std::size_t headlen = headroom();
+ if (length_ > 0) {
+ assert(data_ != nullptr);
+ memcpy(buf + headlen, data_, length_);
+ }
+
+ // Release our reference on the old buffer
+ decrementRefcount();
+ // Make sure flag_maybe_shared and flag_free_shared_info are all cleared.
+ setFlagsAndSharedInfo(0, sharedInfo);
+
+ // Update the buffer pointers to point to the new buffer
+ data_ = buf + headlen;
+ buf_ = buf;
+}
+
+void MemBuf::unshareChained() {
+ // unshareChained() should only be called if we are part of a chain of
+ // multiple MemBufs. The caller should have already verified this.
+ assert(isChained());
+
+ MemBuf* current = this;
+ while (true) {
+ if (current->isSharedOne()) {
+ // we have to unshare
+ break;
+ }
+
+ current = current->next_;
+ if (current == this) {
+ // None of the MemBufs in the chain are shared,
+ // so return without doing anything
+ return;
+ }
+ }
+
+ // We have to unshare. Let coalesceSlow() do the work.
+ coalesceSlow();
+}
+
+void MemBuf::markExternallyShared() {
+ MemBuf* current = this;
+ do {
+ current->markExternallySharedOne();
+ current = current->next_;
+ } while (current != this);
+}
+
+void MemBuf::makeManagedChained() {
+ assert(isChained());
+
+ MemBuf* current = this;
+ while (true) {
+ current->makeManagedOne();
+ current = current->next_;
+ if (current == this) {
+ break;
+ }
+ }
+}
+
+void MemBuf::coalesceSlow() {
+ // coalesceSlow() should only be called if we are part of a chain of multiple
+ // MemBufs. The caller should have already verified this.
+
+ // Compute the length of the entire chain
+ std::size_t new_length = 0;
+ MemBuf* end = this;
+ do {
+ new_length += end->length_;
+ end = end->next_;
+ } while (end != this);
+
+ coalesceAndReallocate(new_length, end);
+ // We should be only element left in the chain now
+}
+
+void MemBuf::coalesceSlow(size_t max_length) {
+ // coalesceSlow() should only be called if we are part of a chain of multiple
+ // MemBufs. The caller should have already verified this.
+
+ // Compute the length of the entire chain
+ std::size_t new_length = 0;
+ MemBuf* end = this;
+ while (true) {
+ new_length += end->length_;
+ end = end->next_;
+ if (new_length >= max_length) {
+ break;
+ }
+ if (end == this) {
+ throw std::overflow_error(
+ "attempted to coalesce more data than "
+ "available");
+ }
+ }
+
+ coalesceAndReallocate(new_length, end);
+ // We should have the requested length now
+}
+
+void MemBuf::coalesceAndReallocate(size_t new_headroom, size_t new_length,
+ MemBuf* end, size_t new_tailroom) {
+ std::size_t new_capacity = new_length + new_headroom + new_tailroom;
+
+ // Allocate space for the coalesced buffer.
+ // We always convert to an external buffer, even if we happened to be an
+ // internal buffer before.
+ uint8_t* newBuf;
+ SharedInfo* newInfo;
+ std::size_t actualCapacity;
+ allocExtBuffer(new_capacity, &newBuf, &newInfo, &actualCapacity);
+
+ // Copy the data into the new buffer
+ uint8_t* new_data = newBuf + new_headroom;
+ uint8_t* p = new_data;
+ MemBuf* current = this;
+ size_t remaining = new_length;
+ do {
+ if (current->length_ > 0) {
+ assert(current->length_ <= remaining);
+ assert(current->data_ != nullptr);
+ remaining -= current->length_;
+ memcpy(p, current->data_, current->length_);
+ p += current->length_;
+ }
+ current = current->next_;
+ } while (current != end);
+ assert(remaining == 0);
+
+ // Point at the new buffer
+ decrementRefcount();
+
+ // Make sure flag_maybe_shared and flag_free_shared_info are all cleared.
+ setFlagsAndSharedInfo(0, newInfo);
+
+ capacity_ = actualCapacity;
+ buf_ = newBuf;
+ data_ = new_data;
+ length_ = new_length;
+
+ // Separate from the rest of our chain.
+ // Since we don't store the unique_ptr returned by separateChain(),
+ // this will immediately delete the returned subchain.
+ if (isChained()) {
+ (void)separateChain(next_, current->prev_);
+ }
+}
+
+void MemBuf::decrementRefcount() {
+ // Externally owned buffers don't have a SharedInfo object and aren't managed
+ // by the reference count
+ SharedInfo* info = sharedInfo();
+ if (!info) {
+ return;
+ }
+
+ // Decrement the refcount
+ uint32_t newcnt = info->refcount.fetch_sub(1, std::memory_order_acq_rel);
+ // Note that fetch_sub() returns the value before we decremented.
+ // If it is 1, we were the only remaining user; if it is greater there are
+ // still other users.
+ if (newcnt > 1) {
+ return;
+ }
+
+ // We were the last user. Free the buffer
+ freeExtBuffer();
+
+ // Free the SharedInfo if it was allocated separately.
+ //
+ // This is only used by takeOwnership().
+ //
+ // To avoid this special case handling in decrementRefcount(), we could have
+ // takeOwnership() set a custom freeFn() that calls the user's free function
+ // then frees the SharedInfo object. (This would require that
+ // takeOwnership() store the user's free function with its allocated
+ // SharedInfo object.) However, handling this specially with a flag seems
+ // like it shouldn't be problematic.
+ if (flags() & flag_free_shared_info) {
+ delete sharedInfo();
+ }
+}
+
+void MemBuf::reserveSlow(std::size_t min_headroom, std::size_t min_tailroom) {
+ size_t new_capacity = (size_t)length_ + min_headroom + min_tailroom;
+
+ // // reserveSlow() is dangerous if anyone else is sharing the buffer, as we
+ // may
+ // // reallocate and free the original buffer. It should only ever be called
+ // if
+ // // we are the only user of the buffer.
+
+ // We'll need to reallocate the buffer.
+ // There are a few options.
+ // - If we have enough total room, move the data around in the buffer
+ // and adjust the data_ pointer.
+ // - If we're using an internal buffer, we'll switch to an external
+ // buffer with enough headroom and tailroom.
+ // - If we have enough headroom (headroom() >= min_headroom) but not too much
+ // (so we don't waste memory), we can try:
+ // - If we don't have too much to copy, we'll use realloc() (note that
+ // realloc might have to copy
+ // headroom + data + tailroom)
+ // - Otherwise, bite the bullet and reallocate.
+ if (headroom() + tailroom() >= min_headroom + min_tailroom) {
+ uint8_t* new_data = writableBuffer() + min_headroom;
+ std::memmove(new_data, data_, length_);
+ data_ = new_data;
+ return;
+ }
+
+ size_t new_allocated_capacity = 0;
+ uint8_t* new_buffer = nullptr;
+ std::size_t new_headroom = 0;
+ std::size_t old_headroom = headroom();
+
+ // If we have a buffer allocated with malloc and we just need more tailroom,
+ // try to use realloc()/xallocx() to grow the buffer in place.
+ SharedInfo* info = sharedInfo();
+ if (info && (info->freeFn == nullptr) && length_ != 0 &&
+ old_headroom >= min_headroom) {
+ size_t head_slack = old_headroom - min_headroom;
+ new_allocated_capacity = goodExtBufferSize(new_capacity + head_slack);
+
+ size_t copySlack = capacity() - length_;
+ if (copySlack * 2 <= length_) {
+ void* p = realloc(buf_, new_allocated_capacity);
+ if (TRANSPORT_EXPECT_FALSE(p == nullptr)) {
+ throw std::bad_alloc();
+ }
+ new_buffer = static_cast<uint8_t*>(p);
+ new_headroom = old_headroom;
+ }
+ }
+
+ // None of the previous reallocation strategies worked (or we're using
+ // an internal buffer). malloc/copy/free.
+ if (new_buffer == nullptr) {
+ new_allocated_capacity = goodExtBufferSize(new_capacity);
+ new_buffer = static_cast<uint8_t*>(malloc(new_allocated_capacity));
+ if (length_ > 0) {
+ assert(data_ != nullptr);
+ memcpy(new_buffer + min_headroom, data_, length_);
+ }
+ if (sharedInfo()) {
+ freeExtBuffer();
+ }
+ new_headroom = min_headroom;
+ }
+
+ std::size_t cap;
+ initExtBuffer(new_buffer, new_allocated_capacity, &info, &cap);
+
+ if (flags() & flag_free_shared_info) {
+ delete sharedInfo();
+ }
+
+ setFlagsAndSharedInfo(0, info);
+ capacity_ = cap;
+ buf_ = new_buffer;
+ data_ = new_buffer + new_headroom;
+ // length_ is unchanged
+}
+
+void MemBuf::freeExtBuffer() {
+ SharedInfo* info = sharedInfo();
+
+ if (info->freeFn) {
+ try {
+ info->freeFn(buf_, info->userData);
+ } catch (...) {
+ // The user's free function should never throw. Otherwise we might
+ // throw from the MemBuf destructor. Other code paths like coalesce()
+ // also assume that decrementRefcount() cannot throw.
+ abort();
+ }
+ } else {
+ free(buf_);
+ }
+}
+
+void MemBuf::allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn) {
+ size_t mallocSize = goodExtBufferSize(minCapacity);
+ uint8_t* buf = static_cast<uint8_t*>(malloc(mallocSize));
+ initExtBuffer(buf, mallocSize, infoReturn, capacityReturn);
+ *bufReturn = buf;
+}
+
+size_t MemBuf::goodExtBufferSize(std::size_t minCapacity) {
+ // Determine how much space we should allocate. We'll store the SharedInfo
+ // for the external buffer just after the buffer itself. (We store it just
+ // after the buffer rather than just before so that the code can still just
+ // use free(buf_) to free the buffer.)
+ size_t minSize = static_cast<size_t>(minCapacity) + sizeof(SharedInfo);
+ // Add room for padding so that the SharedInfo will be aligned on an 8-byte
+ // boundary.
+ minSize = (minSize + 7) & ~7;
+
+ // Use goodMallocSize() to bump up the capacity to a decent size to request
+ // from malloc, so we can use all of the space that malloc will probably give
+ // us anyway.
+ return minSize;
+}
+
+void MemBuf::initExtBuffer(uint8_t* buf, size_t mallocSize,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn) {
+ // Find the SharedInfo storage at the end of the buffer
+ // and construct the SharedInfo.
+ uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo);
+ SharedInfo* sharedInfo = new (infoStart) SharedInfo;
+
+ *capacityReturn = std::size_t(infoStart - buf);
+ *infoReturn = sharedInfo;
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/membuf.h b/libtransport/src/hicn/transport/utils/membuf.h
new file mode 100755
index 000000000..944237e2b
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/membuf.h
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * The code in this file if adapated from the IOBuf of folly:
+ * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <atomic>
+#include <cassert>
+#include <cinttypes>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+// Ignore shadowing warnings within this file, so includers can use -Wshadow.
+TRANSPORT_GNU_DISABLE_WARNING("-Wshadow")
+
+namespace utils {
+
+class MemBuf {
+ public:
+ enum CreateOp { CREATE };
+ enum WrapBufferOp { WRAP_BUFFER };
+ enum TakeOwnershipOp { TAKE_OWNERSHIP };
+ enum CopyBufferOp { COPY_BUFFER };
+
+ typedef void (*FreeFunction)(void* buf, void* userData);
+
+ static std::unique_ptr<MemBuf> create(std::size_t capacity);
+ MemBuf(CreateOp, std::size_t capacity);
+
+ /**
+ * Create a new MemBuf, using a single memory allocation to allocate space
+ * for both the MemBuf object and the data storage space.
+ *
+ * This saves one memory allocation. However, it can be wasteful if you
+ * later need to grow the buffer using reserve(). If the buffer needs to be
+ * reallocated, the space originally allocated will not be freed() until the
+ * MemBuf object itself is also freed. (It can also be slightly wasteful in
+ * some cases where you clone this MemBuf and then free the original MemBuf.)
+ */
+ static std::unique_ptr<MemBuf> createCombined(std::size_t capacity);
+
+ /**
+ * Create a new IOBuf, using separate memory allocations for the IOBuf object
+ * for the IOBuf and the data storage space.
+ *
+ * This requires two memory allocations, but saves space in the long run
+ * if you know that you will need to reallocate the data buffer later.
+ */
+ static std::unique_ptr<MemBuf> createSeparate(std::size_t capacity);
+
+ /**
+ * Allocate a new MemBuf chain with the requested total capacity, allocating
+ * no more than maxBufCapacity to each buffer.
+ */
+ static std::unique_ptr<MemBuf> createChain(size_t totalCapacity,
+ std::size_t maxBufCapacity);
+
+ static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true) {
+ return takeOwnership(buf, capacity, capacity, freeFn, userData,
+ freeOnError);
+ }
+
+ MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity,
+ FreeFunction freeFn = nullptr, void* userData = nullptr,
+ bool freeOnError = true)
+ : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {}
+
+ static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+ std::size_t length,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true);
+
+ MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length,
+ FreeFunction freeFn = nullptr, void* userData = nullptr,
+ bool freeOnError = true);
+
+ static std::unique_ptr<MemBuf> wrapBuffer(const void* buf,
+ std::size_t capacity);
+
+ static MemBuf wrapBufferAsValue(const void* buf,
+ std::size_t capacity) noexcept;
+
+ MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept;
+
+ /**
+ * Convenience function to create a new MemBuf object that copies data from a
+ * user-supplied buffer, optionally allocating a given amount of
+ * headroom and tailroom.
+ */
+ static std::unique_ptr<MemBuf> copyBuffer(const void* buf, std::size_t size,
+ std::size_t headroom = 0,
+ std::size_t minTailroom = 0);
+
+ MemBuf(CopyBufferOp op, const void* buf, std::size_t size,
+ std::size_t headroom = 0, std::size_t minTailroom = 0);
+
+ /**
+ * Convenience function to free a chain of MemBufs held by a unique_ptr.
+ */
+ static void destroy(std::unique_ptr<MemBuf>&& data) {
+ auto destroyer = std::move(data);
+ }
+
+ ~MemBuf();
+
+ bool empty() const;
+
+ const uint8_t* data() const { return data_; }
+
+ uint8_t* writableData() { return data_; }
+
+ const uint8_t* tail() const { return data_ + length_; }
+
+ uint8_t* writableTail() { return data_ + length_; }
+
+ std::size_t length() const { return length_; }
+
+ std::size_t headroom() const { return std::size_t(data_ - buffer()); }
+
+ std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); }
+
+ const uint8_t* buffer() const { return buf_; }
+
+ uint8_t* writableBuffer() { return buf_; }
+
+ const uint8_t* bufferEnd() const { return buf_ + capacity_; }
+
+ std::size_t capacity() const { return capacity_; }
+
+ MemBuf* next() { return next_; }
+
+ const MemBuf* next() const { return next_; }
+
+ MemBuf* prev() { return prev_; }
+
+ const MemBuf* prev() const { return prev_; }
+
+ /**
+ * Shift the data forwards in the buffer.
+ *
+ * This shifts the data pointer forwards in the buffer to increase the
+ * headroom. This is commonly used to increase the headroom in a newly
+ * allocated buffer.
+ *
+ * The caller is responsible for ensuring that there is sufficient
+ * tailroom in the buffer before calling advance().
+ *
+ * If there is a non-zero data length, advance() will use memmove() to shift
+ * the data forwards in the buffer. In this case, the caller is responsible
+ * for making sure the buffer is unshared, so it will not affect other MemBufs
+ * that may be sharing the same underlying buffer.
+ */
+ void advance(std::size_t amount) {
+ // In debug builds, assert if there is a problem.
+ assert(amount <= tailroom());
+
+ if (length_ > 0) {
+ memmove(data_ + amount, data_, length_);
+ }
+ data_ += amount;
+ }
+
+ /**
+ * Shift the data backwards in the buffer.
+ *
+ * The caller is responsible for ensuring that there is sufficient headroom
+ * in the buffer before calling retreat().
+ *
+ * If there is a non-zero data length, retreat() will use memmove() to shift
+ * the data backwards in the buffer. In this case, the caller is responsible
+ * for making sure the buffer is unshared, so it will not affect other MemBufs
+ * that may be sharing the same underlying buffer.
+ */
+ void retreat(std::size_t amount) {
+ // In debug builds, assert if there is a problem.
+ assert(amount <= headroom());
+
+ if (length_ > 0) {
+ memmove(data_ - amount, data_, length_);
+ }
+ data_ -= amount;
+ }
+
+ void prepend(std::size_t amount) {
+ data_ -= amount;
+ length_ += amount;
+ }
+
+ void append(std::size_t amount) { length_ += amount; }
+
+ void trimStart(std::size_t amount) {
+ data_ += amount;
+ length_ -= amount;
+ }
+
+ void trimEnd(std::size_t amount) { length_ -= amount; }
+
+ void clear() {
+ data_ = writableBuffer();
+ length_ = 0;
+ }
+
+ void reserve(std::size_t minHeadroom, std::size_t minTailroom) {
+ // Maybe we don't need to do anything.
+ if (headroom() >= minHeadroom && tailroom() >= minTailroom) {
+ return;
+ }
+ // If the buffer is empty but we have enough total room (head + tail),
+ // move the data_ pointer around.
+ if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) {
+ data_ = writableBuffer() + minHeadroom;
+ return;
+ }
+ // Bah, we have to do actual work.
+ reserveSlow(minHeadroom, minTailroom);
+ }
+
+ bool isChained() const {
+ assert((next_ == this) == (prev_ == this));
+ return next_ != this;
+ }
+
+ size_t countChainElements() const;
+
+ std::size_t computeChainDataLength() const;
+
+ void prependChain(std::unique_ptr<MemBuf>&& iobuf);
+
+ void appendChain(std::unique_ptr<MemBuf>&& iobuf) {
+ // Just use prependChain() on the next element in our chain
+ next_->prependChain(std::move(iobuf));
+ }
+
+ std::unique_ptr<MemBuf> unlink() {
+ next_->prev_ = prev_;
+ prev_->next_ = next_;
+ prev_ = this;
+ next_ = this;
+ return std::unique_ptr<MemBuf>(this);
+ }
+
+ /**
+ * Remove this MemBuf from its current chain and return a unique_ptr to
+ * the MemBuf that formerly followed it in the chain.
+ */
+ std::unique_ptr<MemBuf> pop() {
+ MemBuf* next = next_;
+ next_->prev_ = prev_;
+ prev_->next_ = next_;
+ prev_ = this;
+ next_ = this;
+ return std::unique_ptr<MemBuf>((next == this) ? nullptr : next);
+ }
+
+ /**
+ * Remove a subchain from this chain.
+ *
+ * Remove the subchain starting at head and ending at tail from this chain.
+ *
+ * Returns a unique_ptr pointing to head. (In other words, ownership of the
+ * head of the subchain is transferred to the caller.) If the caller ignores
+ * the return value and lets the unique_ptr be destroyed, the subchain will
+ * be immediately destroyed.
+ *
+ * The subchain referenced by the specified head and tail must be part of the
+ * same chain as the current MemBuf, but must not contain the current MemBuf.
+ * However, the specified head and tail may be equal to each other (i.e.,
+ * they may be a subchain of length 1).
+ */
+ std::unique_ptr<MemBuf> separateChain(MemBuf* head, MemBuf* tail) {
+ assert(head != this);
+ assert(tail != this);
+
+ head->prev_->next_ = tail->next_;
+ tail->next_->prev_ = head->prev_;
+
+ head->prev_ = tail;
+ tail->next_ = head;
+
+ return std::unique_ptr<MemBuf>(head);
+ }
+
+ /**
+ * Return true if at least one of the MemBufs in this chain are shared,
+ * or false if all of the MemBufs point to unique buffers.
+ *
+ * Use isSharedOne() to only check this MemBuf rather than the entire chain.
+ */
+ bool isShared() const {
+ const MemBuf* current = this;
+ while (true) {
+ if (current->isSharedOne()) {
+ return true;
+ }
+ current = current->next_;
+ if (current == this) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Return true if all MemBufs in this chain are managed by the usual
+ * refcounting mechanism (and so the lifetime of the underlying memory
+ * can be extended by clone()).
+ */
+ bool isManaged() const {
+ const MemBuf* current = this;
+ while (true) {
+ if (!current->isManagedOne()) {
+ return false;
+ }
+ current = current->next_;
+ if (current == this) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Return true if this MemBuf is managed by the usual refcounting mechanism
+ * (and so the lifetime of the underlying memory can be extended by
+ * cloneOne()).
+ */
+ bool isManagedOne() const { return sharedInfo(); }
+
+ /**
+ * Return true if other MemBufs are also pointing to the buffer used by this
+ * MemBuf, and false otherwise.
+ *
+ * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the
+ * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned
+ * from such an MemBuf), it is always considered shared.
+ *
+ * This only checks the current MemBuf, and not other MemBufs in the chain.
+ */
+ bool isSharedOne() const {
+ // If this is a user-owned buffer, it is always considered shared
+ if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) {
+ return true;
+ }
+
+ if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) {
+ return true;
+ }
+
+ if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) {
+ return false;
+ }
+
+ // flag_maybe_shared is set, so we need to check the reference count.
+ // (Checking the reference count requires an atomic operation, which is why
+ // we prefer to only check flag_maybe_shared if possible.)
+ bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
+ if (!shared) {
+ // we're the last one left
+ clearFlags(flag_maybe_shared);
+ }
+ return shared;
+ }
+
+ /**
+ * Ensure that this MemBuf has a unique buffer that is not shared by other
+ * MemBufs.
+ *
+ * unshare() operates on an entire chain of MemBuf objects. If the chain is
+ * shared, it may also coalesce the chain when making it unique. If the
+ * chain is coalesced, subsequent MemBuf objects in the current chain will be
+ * automatically deleted.
+ *
+ * Note that buffers owned by other (non-MemBuf) users are automatically
+ * considered shared.
+ *
+ * Throws std::bad_alloc on error. On error the MemBuf chain will be
+ * unmodified.
+ *
+ * Currently unshare may also throw std::overflow_error if it tries to
+ * coalesce. (TODO: In the future it would be nice if unshare() were smart
+ * enough not to coalesce the entire buffer if the data is too large.
+ * However, in practice this seems unlikely to become an issue.)
+ */
+ void unshare() {
+ if (isChained()) {
+ unshareChained();
+ } else {
+ unshareOne();
+ }
+ }
+
+ /**
+ * Ensure that this MemBuf has a unique buffer that is not shared by other
+ * MemBufs.
+ *
+ * unshareOne() operates on a single MemBuf object. This MemBuf will have a
+ * unique buffer after unshareOne() returns, but other MemBufs in the chain
+ * may still be shared after unshareOne() returns.
+ *
+ * Throws std::bad_alloc on error. On error the MemBuf will be unmodified.
+ */
+ void unshareOne() {
+ if (isSharedOne()) {
+ unshareOneSlow();
+ }
+ }
+
+ /**
+ * Mark the underlying buffers in this chain as shared with external memory
+ * management mechanism. This will make isShared() always returns true.
+ *
+ * This function is not thread-safe, and only safe to call immediately after
+ * creating an MemBuf, before it has been shared with other threads.
+ */
+ void markExternallyShared();
+
+ /**
+ * Mark the underlying buffer that this MemBuf refers to as shared with
+ * external memory management mechanism. This will make isSharedOne() always
+ * returns true.
+ *
+ * This function is not thread-safe, and only safe to call immediately after
+ * creating an MemBuf, before it has been shared with other threads.
+ */
+ void markExternallySharedOne() {
+ SharedInfo* info = sharedInfo();
+ if (info) {
+ info->externallyShared = true;
+ }
+ }
+
+ /**
+ * Ensure that the memory that MemBufs in this chain refer to will continue to
+ * be allocated for as long as the MemBufs of the chain (or any clone()s
+ * created from this point onwards) is alive.
+ *
+ * This only has an effect for user-owned buffers (created with the
+ * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+ * those buffers are unshared.
+ */
+ void makeManaged() {
+ if (isChained()) {
+ makeManagedChained();
+ } else {
+ makeManagedOne();
+ }
+ }
+
+ /**
+ * Ensure that the memory that this MemBuf refers to will continue to be
+ * allocated for as long as this MemBuf (or any clone()s created from this
+ * point onwards) is alive.
+ *
+ * This only has an effect for user-owned buffers (created with the
+ * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+ * those buffers are unshared.
+ */
+ void makeManagedOne() {
+ if (!isManagedOne()) {
+ // We can call the internal function directly; unmanaged implies shared.
+ unshareOneSlow();
+ }
+ }
+
+ // /**
+ // * Coalesce this MemBuf chain into a single buffer.
+ // *
+ // * This method moves all of the data in this MemBuf chain into a single
+ // * contiguous buffer, if it is not already in one buffer. After coalesce()
+ // * returns, this MemBuf will be a chain of length one. Other MemBufs in
+ // the
+ // * chain will be automatically deleted.
+ // *
+ // * After coalescing, the MemBuf will have at least as much headroom as the
+ // * first MemBuf in the chain, and at least as much tailroom as the last
+ // MemBuf
+ // * in the chain.
+ // *
+ // * Throws std::bad_alloc on error. On error the MemBuf chain will be
+ // * unmodified.
+ // *
+ // * Returns ByteRange that points to the data MemBuf stores.
+ // */
+ // ByteRange coalesce() {
+ // const std::size_t newHeadroom = headroom();
+ // const std::size_t newTailroom = prev()->tailroom();
+ // return coalesceWithHeadroomTailroom(newHeadroom, newTailroom);
+ // }
+
+ // /**
+ // * This is similar to the coalesce() method, except this allows to set a
+ // * headroom and tailroom after coalescing.
+ // *
+ // * Returns ByteRange that points to the data MemBuf stores.
+ // */
+ // ByteRange coalesceWithHeadroomTailroom(
+ // std::size_t newHeadroom,
+ // std::size_t newTailroom) {
+ // if (isChained()) {
+ // coalesceAndReallocate(
+ // newHeadroom, computeChainDataLength(), this, newTailroom);
+ // }
+ // return ByteRange(data_, length_);
+ // }
+
+ /**
+ * Ensure that this chain has at least maxLength bytes available as a
+ * contiguous memory range.
+ *
+ * This method coalesces whole buffers in the chain into this buffer as
+ * necessary until this buffer's length() is at least maxLength.
+ *
+ * After coalescing, the MemBuf will have at least as much headroom as the
+ * first MemBuf in the chain, and at least as much tailroom as the last MemBuf
+ * that was coalesced.
+ *
+ * Throws std::bad_alloc or std::overflow_error on error. On error the MemBuf
+ * chain will be unmodified. Throws std::overflow_error if maxLength is
+ * longer than the total chain length.
+ *
+ * Upon return, either enough of the chain was coalesced into a contiguous
+ * region, or the entire chain was coalesced. That is,
+ * length() >= maxLength || !isChained() is true.
+ */
+ void gather(std::size_t maxLength) {
+ if (!isChained() || length_ >= maxLength) {
+ return;
+ }
+ coalesceSlow(maxLength);
+ }
+
+ /**
+ * Return a new MemBuf chain sharing the same data as this chain.
+ *
+ * The new MemBuf chain will normally point to the same underlying data
+ * buffers as the original chain. (The one exception to this is if some of
+ * the MemBufs in this chain contain small internal data buffers which cannot
+ * be shared.)
+ */
+ std::unique_ptr<MemBuf> clone() const;
+
+ /**
+ * Similar to clone(). But returns MemBuf by value rather than heap-allocating
+ * it.
+ */
+ MemBuf cloneAsValue() const;
+
+ /**
+ * Return a new MemBuf with the same data as this MemBuf.
+ *
+ * The new MemBuf returned will not be part of a chain (even if this MemBuf is
+ * part of a larger chain).
+ */
+ std::unique_ptr<MemBuf> cloneOne() const;
+
+ /**
+ * Similar to cloneOne(). But returns MemBuf by value rather than
+ * heap-allocating it.
+ */
+ MemBuf cloneOneAsValue() const;
+
+ /**
+ * Return a new unchained MemBuf that may share the same data as this chain.
+ *
+ * If the MemBuf chain is not chained then the new MemBuf will point to the
+ * same underlying data buffer as the original chain. Otherwise, it will clone
+ * and coalesce the MemBuf chain.
+ *
+ * The new MemBuf will have at least as much headroom as the first MemBuf in
+ * the chain, and at least as much tailroom as the last MemBuf in the chain.
+ *
+ * Throws std::bad_alloc on error.
+ */
+ std::unique_ptr<MemBuf> cloneCoalesced() const;
+
+ /**
+ * This is similar to the cloneCoalesced() method, except this allows to set a
+ * headroom and tailroom for the new MemBuf.
+ */
+ std::unique_ptr<MemBuf> cloneCoalescedWithHeadroomTailroom(
+ std::size_t newHeadroom, std::size_t newTailroom) const;
+
+ /**
+ * Similar to cloneCoalesced(). But returns MemBuf by value rather than
+ * heap-allocating it.
+ */
+ MemBuf cloneCoalescedAsValue() const;
+
+ /**
+ * This is similar to the cloneCoalescedAsValue() method, except this allows
+ * to set a headroom and tailroom for the new MemBuf.
+ */
+ MemBuf cloneCoalescedAsValueWithHeadroomTailroom(
+ std::size_t newHeadroom, std::size_t newTailroom) const;
+
+ /**
+ * Similar to Clone(). But use other as the head node. Other nodes in the
+ * chain (if any) will be allocted on heap.
+ */
+ void cloneInto(MemBuf& other) const { other = cloneAsValue(); }
+
+ /**
+ * Similar to CloneOne(). But to fill an existing MemBuf instead of a new
+ * MemBuf.
+ */
+ void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); }
+
+ /**
+ * Return an iovector suitable for e.g. writev()
+ *
+ * auto iov = buf->getIov();
+ * auto xfer = writev(fd, iov.data(), iov.size());
+ *
+ * Naturally, the returned iovector is invalid if you modify the buffer
+ * chain.
+ */
+ std::vector<struct iovec> getIov() const;
+
+ /**
+ * Update an existing iovec array with the MemBuf data.
+ *
+ * New iovecs will be appended to the existing vector; anything already
+ * present in the vector will be left unchanged.
+ *
+ * Naturally, the returned iovec data will be invalid if you modify the
+ * buffer chain.
+ */
+ void appendToIov(std::vector<struct iovec>* iov) const;
+
+ /**
+ * Fill an iovec array with the MemBuf data.
+ *
+ * Returns the number of iovec filled. If there are more buffer than
+ * iovec, returns 0. This version is suitable to use with stack iovec
+ * arrays.
+ *
+ * Naturally, the filled iovec data will be invalid if you modify the
+ * buffer chain.
+ */
+ size_t fillIov(struct iovec* iov, size_t len) const;
+
+ /**
+ * A helper that wraps a number of iovecs into an MemBuf chain. If count ==
+ * 0, then a zero length buf is returned. This function never returns
+ * nullptr.
+ */
+ static std::unique_ptr<MemBuf> wrapIov(const iovec* vec, size_t count);
+
+ /**
+ * A helper that takes ownerships a number of iovecs into an MemBuf chain. If
+ * count == 0, then a zero length buf is returned. This function never
+ * returns nullptr.
+ */
+ static std::unique_ptr<MemBuf> takeOwnershipIov(const iovec* vec,
+ size_t count,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true);
+
+ /*
+ * Overridden operator new and delete.
+ * These perform specialized memory management to help support
+ * createCombined(), which allocates MemBuf objects together with the buffer
+ * data.
+ */
+ void* operator new(size_t size);
+ void* operator new(size_t size, void* ptr);
+ void operator delete(void* ptr);
+ void operator delete(void* ptr, void* placement);
+
+ // /**
+ // * Iteration support: a chain of MemBufs may be iterated through using
+ // * STL-style iterators over const ByteRanges. Iterators are only
+ // invalidated
+ // * if the MemBuf that they currently point to is removed.
+ // */
+ // Iterator cbegin() const;
+ // Iterator cend() const;
+ // Iterator begin() const;
+ // Iterator end() const;
+
+ /**
+ * Allocate a new null buffer.
+ *
+ * This can be used to allocate an empty MemBuf on the stack. It will have no
+ * space allocated for it. This is generally useful only to later use move
+ * assignment to fill out the MemBuf.
+ */
+ MemBuf() noexcept;
+
+ /**
+ * Move constructor and assignment operator.
+ *
+ * In general, you should only ever move the head of an MemBuf chain.
+ * Internal nodes in an MemBuf chain are owned by the head of the chain, and
+ * should not be moved from. (Technically, nothing prevents you from moving
+ * a non-head node, but the moved-to node will replace the moved-from node in
+ * the chain. This has implications for ownership, since non-head nodes are
+ * owned by the chain head. You are then responsible for relinquishing
+ * ownership of the moved-to node, and manually deleting the moved-from
+ * node.)
+ *
+ * With the move assignment operator, the destination of the move should be
+ * the head of an MemBuf chain or a solitary MemBuf not part of a chain. If
+ * the move destination is part of a chain, all other MemBufs in the chain
+ * will be deleted.
+ */
+ MemBuf(MemBuf&& other) noexcept;
+ MemBuf& operator=(MemBuf&& other) noexcept;
+
+ MemBuf(const MemBuf& other);
+ MemBuf& operator=(const MemBuf& other);
+
+ private:
+ enum FlagsEnum : uintptr_t {
+ // Adding any more flags would not work on 32-bit architectures,
+ // as these flags are stashed in the least significant 2 bits of a
+ // max-align-aligned pointer.
+ flag_free_shared_info = 0x1,
+ flag_maybe_shared = 0x2,
+ flag_mask = flag_free_shared_info | flag_maybe_shared
+ };
+
+ struct SharedInfo {
+ SharedInfo();
+ SharedInfo(FreeFunction fn, void* arg);
+
+ // A pointer to a function to call to free the buffer when the refcount
+ // hits 0. If this is null, free() will be used instead.
+ FreeFunction freeFn;
+ void* userData;
+ std::atomic<uint32_t> refcount;
+ bool externallyShared{false};
+ };
+ // Helper structs for use by operator new and delete
+ struct HeapPrefix;
+ struct HeapStorage;
+ struct HeapFullStorage;
+
+ /**
+ * Create a new MemBuf pointing to an external buffer.
+ *
+ * The caller is responsible for holding a reference count for this new
+ * MemBuf. The MemBuf constructor does not automatically increment the
+ * reference count.
+ */
+ struct InternalConstructor {}; // avoid conflicts
+ MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
+ std::size_t capacity, uint8_t* data, std::size_t length) noexcept;
+
+ void unshareOneSlow();
+ void unshareChained();
+ void makeManagedChained();
+ void coalesceSlow();
+ void coalesceSlow(size_t maxLength);
+ // newLength must be the entire length of the buffers between this and
+ // end (no truncation)
+ void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end,
+ size_t newTailroom);
+ void coalesceAndReallocate(size_t newLength, MemBuf* end) {
+ coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom());
+ }
+ void decrementRefcount();
+ void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
+ void freeExtBuffer();
+
+ static size_t goodExtBufferSize(std::size_t minCapacity);
+ static void initExtBuffer(uint8_t* buf, size_t mallocSize,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn);
+ static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn);
+ static void releaseStorage(HeapStorage* storage, uint16_t freeFlags);
+ static void freeInternalBuf(void* buf, void* userData);
+
+ /*
+ * Member variables
+ */
+
+ /*
+ * Links to the next and the previous MemBuf in this chain.
+ *
+ * The chain is circularly linked (the last element in the chain points back
+ * at the head), and next_ and prev_ can never be null. If this MemBuf is the
+ * only element in the chain, next_ and prev_ will both point to this.
+ */
+ MemBuf* next_{this};
+ MemBuf* prev_{this};
+
+ /*
+ * A pointer to the start of the data referenced by this MemBuf, and the
+ * length of the data.
+ *
+ * This may refer to any subsection of the actual buffer capacity.
+ */
+ uint8_t* data_{nullptr};
+ uint8_t* buf_{nullptr};
+ std::size_t length_{0};
+ std::size_t capacity_{0};
+
+ // Pack flags in least significant 2 bits, sharedInfo in the rest
+ mutable uintptr_t flags_and_shared_info_{0};
+
+ static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags,
+ SharedInfo* info) {
+ uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+ return flags | uinfo;
+ }
+
+ inline SharedInfo* sharedInfo() const {
+ return reinterpret_cast<SharedInfo*>(flags_and_shared_info_ & ~flag_mask);
+ }
+
+ inline void setSharedInfo(SharedInfo* info) {
+ uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+ flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo;
+ }
+
+ inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; }
+
+ // flags_ are changed from const methods
+ inline void setFlags(uintptr_t flags) const {
+ flags_and_shared_info_ |= flags;
+ }
+
+ inline void clearFlags(uintptr_t flags) const {
+ flags_and_shared_info_ &= ~flags;
+ }
+
+ inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) {
+ flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info);
+ }
+
+ struct DeleterBase {
+ virtual ~DeleterBase() {}
+ virtual void dispose(void* p) = 0;
+ };
+
+ template <class UniquePtr>
+ struct UniquePtrDeleter : public DeleterBase {
+ typedef typename UniquePtr::pointer Pointer;
+ typedef typename UniquePtr::deleter_type Deleter;
+
+ explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {}
+ void dispose(void* p) override {
+ try {
+ deleter_(static_cast<Pointer>(p));
+ delete this;
+ } catch (...) {
+ abort();
+ }
+ }
+
+ private:
+ Deleter deleter_;
+ };
+
+ static void freeUniquePtrBuffer(void* ptr, void* userData) {
+ static_cast<DeleterBase*>(userData)->dispose(ptr);
+ }
+};
+
+// template <class UniquePtr>
+// typename std::enable_if<
+// detail::IsUniquePtrToSL<UniquePtr>::value,
+// std::unique_ptr<MemBuf>>::type
+// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) {
+// size_t size = count * sizeof(typename UniquePtr::element_type);
+// auto deleter = new UniquePtrDeleter<UniquePtr>(buf.get_deleter());
+// return takeOwnership(
+// buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter);
+// }
+
+inline std::unique_ptr<MemBuf> MemBuf::copyBuffer(const void* data,
+ std::size_t size,
+ std::size_t headroom,
+ std::size_t minTailroom) {
+ std::size_t capacity = headroom + size + minTailroom;
+ std::unique_ptr<MemBuf> buf = MemBuf::create(capacity);
+ buf->advance(headroom);
+ if (size != 0) {
+ memcpy(buf->writableData(), data, size);
+ }
+ buf->append(size);
+ return buf;
+}
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/min_filter.h b/libtransport/src/hicn/transport/utils/min_filter.h
new file mode 100755
index 000000000..acb081edc
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/min_filter.h
@@ -0,0 +1,56 @@
+/*
+ * 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.sudo make instamake install
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <deque>
+#include <iostream>
+#include <set>
+#include <type_traits>
+#include <vector>
+
+namespace utils {
+
+template <typename T>
+class MinFilter {
+ public:
+ MinFilter(std::size_t size) : size_(size) {}
+
+ std::size_t size() { return by_arrival_.size(); }
+
+ template <typename R>
+ TRANSPORT_ALWAYS_INLINE void pushBack(R&& value) {
+ if (by_arrival_.size() > size_) {
+ by_order_.erase(by_arrival_.back());
+ by_arrival_.pop_back();
+ }
+
+ by_arrival_.push_front(by_order_.insert(std::forward<R>(value)));
+ }
+
+ TRANSPORT_ALWAYS_INLINE const T& begin() { return *by_order_.cbegin(); }
+
+ TRANSPORT_ALWAYS_INLINE const T& rBegin() { return *by_order_.crbegin(); }
+
+ private:
+ std::multiset<T> by_order_;
+ std::deque<typename std::multiset<T>::const_iterator> by_arrival_;
+ std::size_t size_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/object_pool.h b/libtransport/src/hicn/transport/utils/object_pool.h
new file mode 100755
index 000000000..d4d8e18d6
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/object_pool.h
@@ -0,0 +1,76 @@
+/*
+ * 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
+
+// TODO
+#include <hicn/transport/utils/spinlock.h>
+
+#include <deque>
+#include <memory>
+#include <mutex>
+
+namespace utils {
+
+template <typename T>
+class ObjectPool {
+ class ObjectDeleter {
+ public:
+ ObjectDeleter(ObjectPool<T> *pool = nullptr) : pool_(pool) {}
+
+ void operator()(T *t) {
+ if (pool_) {
+ pool_->add(t);
+ } else {
+ delete t;
+ }
+ }
+
+ private:
+ ObjectPool<T> *pool_;
+ };
+
+ public:
+ using Ptr = std::unique_ptr<T, ObjectDeleter>;
+
+ ObjectPool() {}
+
+ std::pair<bool, Ptr> get() {
+ if (object_pool_.empty()) {
+ return std::make_pair<bool, Ptr>(false, makePtr(nullptr));
+ }
+
+ utils::SpinLock::Acquire locked(object_pool_lock_);
+ auto ret = std::move(object_pool_.front());
+ object_pool_.pop_front();
+ return std::make_pair<bool, Ptr>(true, std::move(ret));
+ }
+
+ void add(T *object) {
+ utils::SpinLock::Acquire locked(object_pool_lock_);
+ object_pool_.emplace_back(makePtr(object));
+ }
+
+ Ptr makePtr(T *object) { return Ptr(object, ObjectDeleter(this)); }
+
+ private:
+ // No copies
+ ObjectPool(const ObjectPool &other) = delete;
+
+ utils::SpinLock object_pool_lock_;
+ std::deque<Ptr> object_pool_;
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/ring_buffer.h b/libtransport/src/hicn/transport/utils/ring_buffer.h
new file mode 100755
index 000000000..52bcd81c4
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/ring_buffer.h
@@ -0,0 +1,129 @@
+/*
+ * 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 <atomic>
+#include <cstddef>
+
+namespace utils {
+
+/**
+ * NOTE: Single consumer single producer ring buffer
+ */
+template <typename Element, std::size_t Size>
+class CircularFifo {
+ public:
+ enum { Capacity = Size + 1 };
+
+ CircularFifo() : tail_(0), head_(0), size_(0) {}
+ virtual ~CircularFifo() {}
+
+ bool push(const Element& item);
+ bool push(Element&& item);
+ bool pop(Element& item);
+
+ bool wasEmpty() const;
+ bool wasFull() const;
+ bool isLockFree() const;
+ std::size_t size() const;
+
+ private:
+ std::size_t increment(std::size_t idx) const;
+ std::atomic<std::size_t> tail_; // tail(input) index
+ Element array_[Capacity];
+ std::atomic<std::size_t> head_; // head(output) index
+ std::atomic<std::size_t> size_;
+};
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(const Element& item) {
+ const auto current_tail = tail_.load(std::memory_order_relaxed);
+ const auto next_tail = increment(current_tail);
+ if (next_tail != head_.load(std::memory_order_acquire)) {
+ array_[current_tail] = item;
+ tail_.store(next_tail, std::memory_order_release);
+ size_++;
+ return true;
+ }
+
+ // full queue
+ return false;
+}
+
+/**
+ * Push by move
+ */
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(Element&& item) {
+ const auto current_tail = tail_.load(std::memory_order_relaxed);
+ const auto next_tail = increment(current_tail);
+ if (next_tail != head_.load(std::memory_order_acquire)) {
+ array_[current_tail] = std::move(item);
+ tail_.store(next_tail, std::memory_order_release);
+ size_++;
+ return true;
+ }
+
+ // full queue
+ return false;
+}
+
+// Pop by Consumer can only update the head
+// (load with relaxed, store with release)
+// the tail must be accessed with at least acquire
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::pop(Element& item) {
+ const auto current_head = head_.load(std::memory_order_relaxed);
+ if (current_head == tail_.load(std::memory_order_acquire)) {
+ return false; // empty queue
+ }
+
+ item = std::move(array_[current_head]);
+ head_.store(increment(current_head), std::memory_order_release);
+ size_--;
+ return true;
+}
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasEmpty() const {
+ // snapshot with acceptance of that this comparison operation is not atomic
+ return (head_.load() == tail_.load());
+}
+
+// snapshot with acceptance that this comparison is not atomic
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasFull() const {
+ const auto next_tail =
+ increment(tail_.load()); // acquire, we dont know who call
+ return (next_tail == head_.load());
+}
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::isLockFree() const {
+ return (tail_.is_lock_free() && head_.is_lock_free());
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::increment(std::size_t idx) const {
+ return (idx + 1) % Capacity;
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::size() const {
+ return size_.load(std::memory_order_relaxed);
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/sharable_vector.h b/libtransport/src/hicn/transport/utils/sharable_vector.h
new file mode 100755
index 000000000..31adff1ad
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/sharable_vector.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+namespace utils {
+
+template <class T>
+class SharableVector : public std::vector<T>,
+ public std::enable_shared_from_this<SharableVector<T>> {
+ public:
+ virtual ~SharableVector(){};
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/signer.cc b/libtransport/src/hicn/transport/utils/signer.cc
new file mode 100755
index 000000000..c11d5e183
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/signer.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * 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/errors/malformed_ahpacket_exception.h>
+#include <hicn/transport/utils/endianess.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/signer.h>
+#include <hicn/transport/utils/key_id.h>
+
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+}
+
+#include <chrono>
+
+#define ALLOW_UNALIGNED_READS 1
+
+namespace utils {
+
+uint8_t Signer::zeros[200] = {0};
+
+/*One signer_ per Private Key*/
+Signer::Signer(PARCKeyStore *keyStore, PARCCryptoSuite suite) {
+ switch (suite) {
+ case PARCCryptoSuite_NULL_CRC32C:
+ break;
+ case PARCCryptoSuite_ECDSA_SHA256:
+ case PARCCryptoSuite_RSA_SHA256:
+ case PARCCryptoSuite_DSA_SHA256:
+ case PARCCryptoSuite_RSA_SHA512:
+ this->signer_ =
+ parcSigner_Create(parcPublicKeySigner_Create(keyStore, suite),
+ PARCPublicKeySignerAsSigner);
+ this->key_id_ = parcSigner_CreateKeyId(this->signer_);
+ break;
+
+ case PARCCryptoSuite_HMAC_SHA512:
+ case PARCCryptoSuite_HMAC_SHA256:
+ default:
+ this->signer_ = parcSigner_Create(
+ parcSymmetricKeySigner_Create((PARCSymmetricKeyStore *)keyStore,
+ parcCryptoSuite_GetCryptoHash(suite)),
+ PARCSymmetricKeySignerAsSigner);
+ this->key_id_ = parcSigner_CreateKeyId(this->signer_);
+ break;
+ }
+}
+
+Signer::Signer(const PARCSigner *signer)
+ : signer_(parcSigner_Acquire(signer)),
+ key_id_(parcSigner_CreateKeyId(this->signer_)) {}
+
+Signer::~Signer() {
+ parcSigner_Release(&signer_);
+ parcKeyId_Release(&key_id_);
+}
+
+void Signer::sign(Packet &packet) {
+ // header chain points to the IP + TCP hicn header
+ utils::MemBuf *header_chain = packet.header_head_;
+ utils::MemBuf * payload_chain = packet.payload_head_;
+ uint8_t *hicn_packet = header_chain->writableData();
+ Packet::Format format = packet.getFormat();
+ std::size_t sign_len_bytes = parcSigner_GetSignatureSize(signer_);
+
+ if (!(format & HFO_AH)) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ // Copy IP+TCP/ICMP header before zeroing them
+ hicn_header_t header_copy;
+ if (format & HFO_INET) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v6_hdr_t));
+ }
+
+ std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+ packet.resetForHash();
+ packet.setSignatureSize(sign_len_bytes);
+
+ /* Fill the hicn_ah header */
+ using namespace std::chrono;
+ auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+ packet.setSignatureTimestamp(now);
+ // *reinterpret_cast<uint64_t*>(ah->signTime) = utils::hton<uint64_t>(now);
+ // // std::memcpy(&ah->hicn_ah.signTime, &sign_time, sizeof(ah->hicn_ah.signTime));
+
+ packet.setValidationAlgorithm(CryptoSuite(parcSigner_GetCryptoSuite(this->signer_)));
+ // ah->validationAlgorithm = parcSigner_GetCryptoSuite(this->signer_);
+
+ KeyId key_id;
+ key_id.first = (uint8_t *)parcBuffer_Overlay((PARCBuffer *) parcKeyId_GetKeyId(this->key_id_), 0);
+ packet.setKeyId(key_id);
+
+ // memcpy(ah->keyId,
+ // parcBuffer_Overlay((PARCBuffer *) parcKeyId_GetKeyId(this->key_id_), 0),
+ // sizeof(_ah_header_t::keyId));
+
+ // Calculate hash
+ utils::CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_));
+ hasher.init();
+ hasher.updateBytes(hicn_packet, header_len);
+ hasher.updateBytes(zeros, sign_len_bytes);
+
+ for (utils::MemBuf *current = payload_chain; current != header_chain; current = current->next()) {
+ hasher.updateBytes(current->data(), current->length());
+ }
+
+ utils::CryptoHash hash = hasher.finalize();
+
+ PARCSignature *signature = parcSigner_SignDigest(this->signer_, hash.hash_);
+ PARCBuffer *buffer = parcSignature_GetSignature(signature);
+
+ PARCByteArray * byte_array = parcBuffer_Array(buffer);
+ uint8_t * bytes = parcByteArray_Array(byte_array);
+ size_t bytes_len = parcBuffer_Remaining(buffer);
+
+ if (bytes_len > sign_len_bytes) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ /* Restore the resetted fields */
+ if (format & HFO_INET) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v6_hdr_t));
+ }
+
+ int offset = sign_len_bytes - bytes_len;
+
+ std::unique_ptr<utils::MemBuf> signature_buffer;
+ std::unique_ptr<utils::MemBuf> tmp_buf = utils::MemBuf::takeOwnership(
+ bytes,
+ bytes_len,
+ bytes_len,
+ [](void* buf, void* userData){ parcSignature_Release((PARCSignature **)&userData); },
+ signature,
+ true);
+
+ if (offset) {
+ signature_buffer = utils::MemBuf::create(offset);
+ memset(signature_buffer->writableData(), 0, offset);
+ signature_buffer->append(offset);
+ signature_buffer->appendChain(std::move(tmp_buf));
+ } else {
+ signature_buffer = std::move(tmp_buf);
+ }
+
+ packet.setSignature(std::move(signature_buffer));
+}
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/signer.h b/libtransport/src/hicn/transport/utils/signer.h
new file mode 100755
index 000000000..7b54b63c8
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/signer.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/packet.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_Signer.h>
+}
+
+namespace utils {
+
+using Packet = transport::core::Packet;
+
+/**
+ * A signer can use a single key (asymmetric or symmetric) to sign a packet.
+ */
+class Signer {
+ friend class Identity;
+
+ public:
+ /**
+ * Create a Signer
+ *
+ * @param keyStore A keystore containing a private key or simmetric key to
+ * use to sign packet with this Signer.
+ * @param suite CryptoSuite to use to verify the signature
+ */
+ Signer(PARCKeyStore *keyStore, PARCCryptoSuite suite);
+
+ Signer(const PARCSigner *signer);
+
+ ~Signer();
+
+ /**
+ * @brief Sign a packet
+ *
+ * This method is general and must be used for Public-private key signature,
+ * HMAC and CRC.
+ *
+ * @param packet A pointer to the header of the packet to sign. Mutable
+ * field in the packet must be set to 0.
+ * @param key_id Indentifier of the key to use to generate the signature.
+ */
+ void sign(Packet &packet);
+
+ private:
+ PARCSigner *signer_;
+ PARCKeyId *key_id_;
+ static uint8_t zeros[200];
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/socket.h b/libtransport/src/hicn/transport/utils/socket.h
new file mode 100755
index 000000000..ab8578f91
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/socket.h
@@ -0,0 +1,267 @@
+/*
+ * 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/facade.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/transport/download_observer.h>
+#include <hicn/transport/transport/socket_options_default_values.h>
+#include <hicn/transport/transport/socket_options_keys.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/identity.h>
+#include <hicn/transport/utils/verifier.h>
+
+#define SOCKET_OPTION_GET 0
+#define SOCKET_OPTION_NOT_GET 1
+#define SOCKET_OPTION_SET 2
+#define SOCKET_OPTION_NOT_SET 3
+#define SOCKET_OPTION_DEFAULT 12345
+
+#define VOID_HANDLER 0
+
+namespace transport {
+
+namespace transport {
+
+template <typename PortalType>
+class Socket;
+class ConsumerSocket;
+class ProducerSocket;
+
+using Interest = core::Interest;
+using ContentObject = core::ContentObject;
+using Name = core::Name;
+using ContentObjectManifest = core::ManifestInline<ContentObject, core::Fixed>;
+using InterestManifest = core::ManifestInline<Interest, core::Fixed>;
+using HashAlgorithm = core::HashAlgorithm;
+using CryptoSuite = utils::CryptoSuite;
+using Identity = utils::Identity;
+using Verifier = utils::Verifier;
+
+using HicnForwarderPortal = core::HicnForwarderPortal;
+
+#ifdef __linux__
+#ifndef __ANDROID__
+using RawSocketPortal = core::RawSocketPortal;
+#endif
+#endif
+
+#ifdef __vpp__
+using VPPForwarderPortal = core::VPPForwarderPortal;
+using BaseSocket = Socket<VPPForwarderPortal>;
+using BasePortal = VPPForwarderPortal;
+#else
+using BaseSocket = Socket<HicnForwarderPortal>;
+using BasePortal = HicnForwarderPortal;
+#endif
+
+using PayloadType = core::PayloadType;
+using Prefix = core::Prefix;
+using Array = utils::Array<uint8_t>;
+
+using ConsumerInterestCallback =
+ std::function<void(ConsumerSocket &, const Interest &)>;
+
+using ConsumerContentCallback =
+ std::function<void(ConsumerSocket &, std::size_t, const std::error_code &)>;
+
+using ConsumerTimerCallback =
+ std::function<void(ConsumerSocket &, std::size_t,
+ std::chrono::milliseconds &, float, uint32_t, uint32_t)>;
+
+using ProducerContentCallback = std::function<void(
+ ProducerSocket &, const std::error_code &, uint64_t bytes_written)>;
+
+using ConsumerContentObjectCallback =
+ std::function<void(ConsumerSocket &, const ContentObject &)>;
+
+using ConsumerContentObjectVerificationCallback =
+ std::function<bool(ConsumerSocket &, const ContentObject &)>;
+
+using ConsumerManifestCallback =
+ std::function<void(ConsumerSocket &, const ContentObjectManifest &)>;
+
+using ProducerContentObjectCallback =
+ std::function<void(ProducerSocket &, ContentObject &)>;
+
+using ProducerInterestCallback =
+ std::function<void(ProducerSocket &, const Interest &)>;
+
+using ProducerInterestCallback =
+ std::function<void(ProducerSocket &, const Interest &)>;
+
+template <typename PortalType>
+class Socket {
+ static_assert(std::is_same<PortalType, HicnForwarderPortal>::value
+#ifdef __linux__
+#ifndef __ANDROID__
+ || std::is_same<PortalType, RawSocketPortal>::value
+#ifdef __vpp__
+ || std::is_same<PortalType, VPPForwarderPortal>::value
+#endif
+#endif
+ ,
+#else
+ ,
+
+#endif
+ "This class is not allowed as Portal");
+
+ public:
+ typedef PortalType Portal;
+
+ virtual asio::io_service &getIoService() = 0;
+
+ virtual void connect() = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ double socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ bool socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ Name socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ProducerInterestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ProducerContentCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerInterestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerContentCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerManifestCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ CryptoSuite socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ const Identity &socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) = 0;
+
+ virtual int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ double &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ bool &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ Name &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ProducerInterestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ConsumerInterestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerContentCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(
+ int socket_option_key, ConsumerManifestCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ProducerContentCallback &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ CryptoSuite &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ Identity &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ std::string &socket_option_value) = 0;
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerTimerCallback &socket_option_value) = 0;
+
+ protected:
+ virtual ~Socket(){};
+
+ protected:
+ std::string output_interface_;
+};
+
+} // namespace transport
+
+} // namespace transport
diff --git a/libtransport/src/hicn/transport/utils/spinlock.h b/libtransport/src/hicn/transport/utils/spinlock.h
new file mode 100755
index 000000000..33e5cda85
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/spinlock.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 <atomic>
+
+namespace utils {
+
+class SpinLock : private std::atomic_flag {
+ public:
+ class Acquire {
+ public:
+ Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); }
+
+ ~Acquire() { spin_lock_.unlock(); }
+
+ // No copies
+ Acquire& operator=(const Acquire&) = delete;
+ Acquire(const Acquire&) = delete;
+
+ private:
+ SpinLock& spin_lock_;
+ };
+
+ SpinLock() : std::atomic_flag(false) {}
+
+ void lock() {
+ // busy-wait
+ while (std::atomic_flag::test_and_set(std::memory_order_acquire))
+ ;
+ }
+
+ void unlock() { clear(std::memory_order_release); }
+
+ bool tryLock() {
+ return std::atomic_flag::test_and_set(std::memory_order_acquire);
+ }
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/stream_buffer.h b/libtransport/src/hicn/transport/utils/stream_buffer.h
new file mode 100755
index 000000000..adfb696f2
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/stream_buffer.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <streambuf>
+
+namespace utils {
+
+template <typename char_type>
+struct ostreambuf
+ : public std::basic_streambuf<char_type, std::char_traits<char_type> > {
+ ostreambuf(char_type* buffer, std::streamsize buffer_length) {
+ // set the "put" pointer the start of the buffer and record it's length.
+ setp(buffer, buffer + buffer_length);
+ }
+};
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.cc b/libtransport/src/hicn/transport/utils/string_tokenizer.cc
new file mode 100755
index 000000000..9d1911080
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/string_tokenizer.cc
@@ -0,0 +1,47 @@
+/*
+ * 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/errors/errors.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+namespace utils {
+
+StringTokenizer::StringTokenizer(const std::string &str)
+ : str_(str), delimiter_(" ") {}
+
+StringTokenizer::StringTokenizer(const std::string &str,
+ const std::string &delim)
+ : str_(str), delimiter_(delim) {}
+
+bool StringTokenizer::hasMoreTokens() {
+ return str_.find(delimiter_) != std::string::npos || !str_.empty();
+}
+
+std::string StringTokenizer::nextToken() {
+ unsigned long pos = str_.find(delimiter_);
+
+ bool token_found = std::string::npos != pos;
+
+ if (!token_found && str_.empty()) {
+ throw errors::TokenizerException();
+ }
+
+ std::string token = str_.substr(0, pos);
+ str_.erase(0, token_found ? pos + delimiter_.length() : pos);
+
+ return token;
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.h b/libtransport/src/hicn/transport/utils/string_tokenizer.h
new file mode 100755
index 000000000..36630eb58
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/string_tokenizer.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <string>
+
+namespace utils {
+
+class StringTokenizer {
+ public:
+ StringTokenizer(const std::string &str);
+ StringTokenizer(const std::string &str, const std::string &delim);
+
+ bool hasMoreTokens();
+ std::string nextToken();
+
+ private:
+ std::string str_;
+ std::string delimiter_;
+};
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/test.h b/libtransport/src/hicn/transport/utils/test.h
new file mode 100755
index 000000000..e3dd619ac
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/test.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <sstream>
+
+namespace testing {
+
+namespace internal {
+
+enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };
+
+extern void ColoredPrintf(GTestColor color, const char *fmt, ...);
+
+} // namespace internal
+
+} // namespace testing
+
+#define PRINTF(...) \
+ do { \
+ testing::internal::ColoredPrintf(testing::internal::COLOR_GREEN, \
+ "[ ] "); \
+ testing::internal::ColoredPrintf(testing::internal::COLOR_YELLOW, \
+ __VA_ARGS__); \
+ } while (0)
+
+// C++ stream interface
+class TestCout : public std::stringstream {
+ public:
+ ~TestCout() {}
+};
+
+#define TEST_COUT TestCout() \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/uri.cc b/libtransport/src/hicn/transport/utils/uri.cc
new file mode 100755
index 000000000..33eb8b45b
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/uri.cc
@@ -0,0 +1,122 @@
+/*
+ * 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/errors/runtime_exception.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace utils {
+
+Uri::Uri() {}
+
+Uri &Uri::parse(const std::string &uri) {
+ if (uri.length() == 0) {
+ throw errors::RuntimeException("Malformed URI.");
+ }
+
+ iterator_t uri_end = uri.end();
+
+ // get query start
+ iterator_t query_start = std::find(uri.begin(), uri_end, '?');
+
+ // protocol
+ iterator_t protocol_start = uri.begin();
+ iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://");
+
+ if (protocol_end != uri_end) {
+ std::string prot = &*(protocol_end);
+ if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) {
+ protocol_ = std::string(protocol_start, protocol_end);
+ protocol_end += 3; // ://
+ } else {
+ protocol_end = uri.begin(); // no protocol
+ }
+ } else {
+ protocol_end = uri.begin(); // no protocol
+ }
+ // host
+ iterator_t host_start = protocol_end;
+ iterator_t path_start =
+ std::find(host_start, uri_end, '/'); // get path_start
+
+ iterator_t host_end = std::find(
+ protocol_end, (path_start != uri_end) ? path_start : query_start,
+ ':'); // check for port
+
+ locator_ = std::string(host_start, host_end);
+
+ // port
+ if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) {
+ host_end++;
+ iterator_t port_end = (path_start != uri_end) ? path_start : query_start;
+ port_ = std::string(host_end, port_end);
+ }
+
+ // path
+ if (path_start != uri_end) {
+ path_ = std::string(path_start, query_start);
+ }
+ // query
+ if (query_start != uri_end) {
+ query_string_ = std::string(query_start, uri.end());
+ }
+
+ return *this;
+}
+
+Uri &Uri::parseProtocolAndLocator(const std::string &locator) {
+ iterator_t total_end = locator.end();
+
+ // protocol
+ iterator_t protocol_start = locator.begin();
+ iterator_t protocol_end =
+ std::find(protocol_start, total_end, ':'); //"://");
+
+ if (protocol_end != total_end) {
+ std::string prot = &*(protocol_end);
+ if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) {
+ protocol_ = std::string(protocol_start, protocol_end);
+ protocol_end += 3; // ://
+ } else {
+ throw errors::RuntimeException("Malformed locator. (Missing \"://\")");
+ }
+ } else {
+ throw errors::RuntimeException("Malformed locator. No protocol specified.");
+ }
+
+ // locator
+ iterator_t host_start = protocol_end;
+ iterator_t host_end = std::find(protocol_end, total_end, '/');
+
+ if (host_start == host_end) {
+ throw errors::RuntimeException(
+ "Malformed locator. Locator name is missing");
+ }
+
+ locator_ = std::string(host_start, host_end);
+
+ return *this;
+}
+
+std::string Uri::getLocator() { return locator_; }
+
+std::string Uri::getPath() { return path_; }
+
+std::string Uri::getPort() { return port_; }
+
+std::string Uri::getProtocol() { return protocol_; }
+
+std::string Uri::getQueryString() { return query_string_; }
+
+} // end namespace utils
diff --git a/libtransport/src/hicn/transport/utils/uri.h b/libtransport/src/hicn/transport/utils/uri.h
new file mode 100755
index 000000000..7c28e8552
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/uri.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <algorithm> // find
+#include <string>
+
+namespace utils {
+
+class Uri {
+ typedef std::string::const_iterator iterator_t;
+
+ public:
+ Uri();
+
+ Uri &parse(const std::string &uri);
+
+ Uri &parseProtocolAndLocator(const std::string &locator);
+
+ std::string getQueryString();
+
+ std::string getPath();
+
+ std::string getProtocol();
+
+ std::string getLocator();
+
+ std::string getPort();
+
+ private:
+ std::string query_string_, path_, protocol_, locator_, port_;
+}; // uri
+
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/verifier.cc b/libtransport/src/hicn/transport/utils/verifier.cc
new file mode 100755
index 000000000..9a3de43c1
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/verifier.cc
@@ -0,0 +1,193 @@
+/*
+ * 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_ahpacket_exception.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/key_id.h>
+#include <hicn/transport/utils/log.h>
+#include <hicn/transport/utils/verifier.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_InMemoryVerifier.h>
+#include <parc/security/parc_Security.h>
+}
+
+#include <sys/stat.h>
+
+namespace utils {
+
+TRANSPORT_ALWAYS_INLINE bool file_exists(const std::string &name) {
+ struct stat buffer;
+ return (stat(name.c_str(), &buffer) == 0);
+}
+
+uint8_t Verifier::zeros[200] = {0};
+
+Verifier::Verifier() {
+ parcSecurity_Init();
+ PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create();
+ this->verifier_ =
+ parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier);
+ parcInMemoryVerifier_Release(&in_memory_verifier);
+}
+
+Verifier::~Verifier() {
+ parcVerifier_Release(&verifier_);
+ parcSecurity_Fini();
+}
+
+/*
+ * TODO: Unsupported in libparc
+ */
+bool Verifier::hasKey(PARCKeyId *keyId) { return false; }
+
+/*
+ * TODO: signal errors without trap.
+ */
+bool Verifier::addKey(PARCKey *key) {
+ parcVerifier_AddKey(this->verifier_, key);
+ return true;
+}
+
+PARCKeyId * Verifier::addKeyFromCertificate(const std::string &file_name) {
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509,
+ PARCContainerEncoding_PEM);
+ parcAssertNotNull(factory, "Expected non-NULL factory");
+
+ if (!file_exists(file_name)) {
+ TRANSPORT_LOGW("Warning! The certificate %s file does not exist",
+ file_name.c_str());
+ return nullptr;
+ }
+
+ PARCCertificate *certificate =
+ parcCertificateFactory_CreateCertificateFromFile(
+ factory, (char *)file_name.c_str(), NULL);
+
+ PARCKey *key = parcCertificate_GetPublicKey(certificate);
+ addKey(key);
+
+ PARCKeyId *ret = parcKeyId_Acquire(parcKey_GetKeyId(key));
+
+ // parcKey_Release(&key);
+ // parcCertificate_Release(&certificate);
+ // parcCertificateFactory_Release(&factory);
+
+ return ret;
+}
+
+int Verifier::verify(const Packet &packet) {
+ bool valid = false;
+
+ // header chain points to the IP + TCP hicn header
+ utils::MemBuf *header_chain = packet.header_head_;
+ utils::MemBuf *payload_chain = packet.payload_head_;
+ uint8_t *hicn_packet = header_chain->writableData();
+ Packet::Format format = packet.getFormat();
+
+ if (!(packet.format_ & HFO_AH)) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ // Copy IP+TCP/ICMP header before zeroing them
+ hicn_header_t header_copy;
+ if (format & HFO_INET) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v6_hdr_t));
+ }
+
+ std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+ PARCCryptoSuite suite =
+ static_cast<PARCCryptoSuite>(packet.getValidationAlgorithm());
+ KeyId _key_id = packet.getKeyId();
+ PARCBuffer *buffer =
+ parcBuffer_Wrap(_key_id.first, _key_id.second, 0, _key_id.second);
+ PARCKeyId *key_id = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int ah_payload_len = header_chain->next()->length();
+ uint8_t *signature = header_chain->next()->writableData();
+
+ // Reset fields that should not appear in the signature
+ const_cast<Packet &>(packet).resetForHash();
+
+ PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite);
+ utils::CryptoHasher hasher(
+ parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype));
+
+ hasher.init()
+ .updateBytes(hicn_packet, header_len)
+ .updateBytes(zeros, ah_payload_len);
+
+ for (utils::MemBuf *current = payload_chain; current != header_chain;
+ current = current->next()) {
+ hasher.updateBytes(current->data(), current->length());
+ }
+
+ utils::CryptoHash hash = hasher.finalize();
+ PARCCryptoHash *hash_computed_locally = hash.hash_;
+
+ PARCBuffer *bits =
+ parcBuffer_Wrap(signature, ah_payload_len, 0, ah_payload_len);
+ parcBuffer_Rewind(bits);
+
+ /* IF the signature algo is ECDSA, the signature might be shorter than the
+ * signature field */
+ PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite);
+ while (algo == PARCSigningAlgorithm_ECDSA && parcBuffer_HasRemaining(bits) &&
+ parcBuffer_GetUint8(bits) == 0)
+ ;
+
+ if (algo == PARCSigningAlgorithm_ECDSA) {
+ parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1);
+ }
+
+ if (!parcBuffer_HasRemaining(bits)) {
+ parcKeyId_Release(&key_id);
+ parcBuffer_Release(&bits);
+ return valid;
+ }
+
+ PARCSignature *signatureToVerify = parcSignature_Create(
+ parcCryptoSuite_GetSigningAlgorithm(suite), hashtype, bits);
+
+ if (algo == PARCSigningAlgorithm_RSA) {
+ parcBuffer_SetPosition(bits, 0);
+ }
+
+ valid = parcVerifier_VerifyDigestSignature(
+ verifier_, key_id, hash_computed_locally, suite, signatureToVerify);
+
+ /* Restore the resetted fields */
+ if (format & HFO_INET) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v6_hdr_t));
+ }
+
+ parcKeyId_Release(&key_id);
+
+ parcBuffer_Release(&bits);
+ parcSignature_Release(&signatureToVerify);
+
+ return valid;
+}
+} // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/verifier.h b/libtransport/src/hicn/transport/utils/verifier.h
new file mode 100755
index 000000000..6313a7240
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/verifier.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/packet.h>
+
+extern "C" {
+#include <parc/security/parc_KeyId.h>
+#include <parc/security/parc_Verifier.h>
+}
+
+namespace utils {
+
+using Packet = transport::core::Packet;
+
+/**
+ * A verifier holds a crypto cache that contains all the keys to use for
+ * verify signatures/hmacs.
+ */
+class Verifier {
+ public:
+ Verifier();
+
+ ~Verifier();
+
+ /**
+ * @brief Check if a key is already in this Verifier.
+ *
+ * A PARCVerifier contains a CryptoCache with a set of key to use for
+ * verification purposes.
+ *
+ * @param keyId Identifier of the key to match in the CryptoCache of the
+ * Verifier.
+ * @return true if the key is found, false otherwise.
+ */
+ bool hasKey(PARCKeyId *keyId);
+
+ /**
+ * @brief Add a key to this Verifier
+ *
+ * @param key to add
+ * @return true if the key was added successfully, false otherwise.
+ */
+ bool addKey(PARCKey *key);
+
+ PARCKeyId *addKeyFromCertificate(const std::string &file_name);
+
+ /**
+ * @brief Verify a Signature
+ *
+ * This method is general and must be used for Public-private key signature,
+ * HMAC and CRC.
+ *
+ * @param signature A pointer to the buffer holding the signature
+ * @param sign_len Lenght of the signature (must be consistent with the type
+ * of the key)
+ * @param bufferSigned A pointer to the packet header signed with
+ * signature. Mutable fields and the signature field in the packet must be
+ * set to 0
+ * @param buf_len Lenght of bufferSigned
+ * @param suite CryptoSuite to use to verify the signature
+ * @param key_id Indentifier of the key to use to verify the signature. The
+ * key must be already present in the Verifier.
+ */
+ int verify(const Packet &packet);
+
+ private:
+ PARCVerifier *verifier_;
+ static uint8_t zeros[200];
+};
+
+} // namespace utils