summaryrefslogtreecommitdiffstats
path: root/libtransport/src
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src')
-rw-r--r--libtransport/src/CMakeLists.txt59
-rw-r--r--libtransport/src/auth/CMakeLists.txt4
-rw-r--r--libtransport/src/auth/crypto_hash.cc201
-rw-r--r--libtransport/src/auth/crypto_suite.cc81
-rw-r--r--libtransport/src/auth/identity.cc286
-rw-r--r--libtransport/src/auth/signer.cc277
-rw-r--r--libtransport/src/auth/verifier.cc427
-rw-r--r--libtransport/src/config.h.in1
-rw-r--r--libtransport/src/core/CMakeLists.txt5
-rw-r--r--libtransport/src/core/connector.cc51
-rw-r--r--libtransport/src/core/connector.h109
-rw-r--r--libtransport/src/core/content_object.cc13
-rw-r--r--libtransport/src/core/fec.cc880
-rw-r--r--libtransport/src/core/forwarder_interface.h149
-rw-r--r--libtransport/src/core/global_configuration.cc40
-rw-r--r--libtransport/src/core/hicn_forwarder_interface.cc135
-rw-r--r--libtransport/src/core/hicn_forwarder_interface.h86
-rw-r--r--libtransport/src/core/hicn_vapi.c235
-rw-r--r--libtransport/src/core/hicn_vapi.h88
-rw-r--r--libtransport/src/core/interest.cc16
-rw-r--r--libtransport/src/core/io_module.cc8
-rw-r--r--libtransport/src/core/local_connector.cc7
-rw-r--r--libtransport/src/core/local_connector.h6
-rw-r--r--libtransport/src/core/manifest_format.h2
-rw-r--r--libtransport/src/core/manifest_format_fixed.cc8
-rw-r--r--libtransport/src/core/manifest_inline.h16
-rw-r--r--libtransport/src/core/memif_connector.cc499
-rw-r--r--libtransport/src/core/memif_connector.h133
-rw-r--r--libtransport/src/core/memif_vapi.c133
-rw-r--r--libtransport/src/core/memif_vapi.h60
-rw-r--r--libtransport/src/core/packet.cc37
-rw-r--r--libtransport/src/core/pending_interest.h7
-rw-r--r--libtransport/src/core/portal.cc5
-rw-r--r--libtransport/src/core/portal.h52
-rw-r--r--libtransport/src/core/raw_socket_connector.cc203
-rw-r--r--libtransport/src/core/raw_socket_connector.h81
-rw-r--r--libtransport/src/core/raw_socket_interface.cc57
-rw-r--r--libtransport/src/core/raw_socket_interface.h62
-rw-r--r--libtransport/src/core/rs.cc370
-rw-r--r--libtransport/src/core/tcp_socket_connector.cc20
-rw-r--r--libtransport/src/core/tcp_socket_connector.h3
-rw-r--r--libtransport/src/core/udp_socket_connector.cc224
-rw-r--r--libtransport/src/core/udp_socket_connector.h85
-rw-r--r--libtransport/src/core/vpp_forwarder_interface.cc226
-rw-r--r--libtransport/src/core/vpp_forwarder_interface.h88
-rw-r--r--libtransport/src/http/CMakeLists.txt2
-rw-r--r--libtransport/src/http/client_connection.cc23
-rw-r--r--libtransport/src/implementation/CMakeLists.txt2
-rw-r--r--libtransport/src/implementation/p2psecure_socket_consumer.cc6
-rw-r--r--libtransport/src/implementation/p2psecure_socket_producer.cc23
-rw-r--r--libtransport/src/implementation/p2psecure_socket_producer.h2
-rw-r--r--libtransport/src/implementation/rtc_socket_producer.cc352
-rw-r--r--libtransport/src/implementation/rtc_socket_producer.h74
-rw-r--r--libtransport/src/implementation/socket_consumer.h4
-rw-r--r--libtransport/src/implementation/socket_producer.h4
-rw-r--r--libtransport/src/implementation/tls_rtc_socket_producer.cc2
-rw-r--r--libtransport/src/implementation/tls_socket_producer.cc11
-rw-r--r--libtransport/src/interfaces/CMakeLists.txt2
-rw-r--r--libtransport/src/interfaces/global_configuration.cc6
-rw-r--r--libtransport/src/interfaces/portal.cc2
-rw-r--r--libtransport/src/io_modules/CMakeLists.txt7
-rw-r--r--libtransport/src/io_modules/forwarder/CMakeLists.txt5
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder.cc31
-rw-r--r--libtransport/src/io_modules/forwarder/forwarder_module.cc6
-rw-r--r--libtransport/src/io_modules/forwarder/global_id_counter.h23
-rw-r--r--libtransport/src/io_modules/forwarder/udp_tunnel.cc50
-rw-r--r--libtransport/src/io_modules/forwarder/udp_tunnel.h3
-rw-r--r--libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc16
-rw-r--r--libtransport/src/io_modules/forwarder/udp_tunnel_listener.h3
-rw-r--r--libtransport/src/io_modules/loopback/CMakeLists.txt6
-rw-r--r--libtransport/src/io_modules/loopback/local_face.cc7
-rw-r--r--libtransport/src/io_modules/loopback/local_face.h3
-rw-r--r--libtransport/src/io_modules/loopback/loopback_module.cc6
-rw-r--r--libtransport/src/io_modules/memif/CMakeLists.txt4
-rw-r--r--libtransport/src/io_modules/memif/hicn_vapi.c1
-rw-r--r--libtransport/src/io_modules/memif/memif_connector.cc35
-rw-r--r--libtransport/src/io_modules/memif/memif_connector.h4
-rw-r--r--libtransport/src/io_modules/memif/vpp_forwarder_module.cc15
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_connector.cc5
-rw-r--r--libtransport/src/io_modules/raw_socket/raw_socket_connector.h3
-rw-r--r--libtransport/src/io_modules/udp/CMakeLists.txt28
-rw-r--r--libtransport/src/io_modules/udp/udp_socket_connector.cc10
-rw-r--r--libtransport/src/io_modules/udp/udp_socket_connector.h3
-rw-r--r--libtransport/src/protocols/CMakeLists.txt16
-rw-r--r--libtransport/src/protocols/byte_stream_reassembly.cc30
-rw-r--r--libtransport/src/protocols/byte_stream_reassembly.h10
-rw-r--r--libtransport/src/protocols/cbr.cc2
-rw-r--r--libtransport/src/protocols/cbr.h3
-rw-r--r--libtransport/src/protocols/data_processing_events.h3
-rw-r--r--libtransport/src/protocols/datagram_reassembly.cc13
-rw-r--r--libtransport/src/protocols/datagram_reassembly.h2
-rw-r--r--libtransport/src/protocols/errors.cc11
-rw-r--r--libtransport/src/protocols/errors.h4
-rw-r--r--libtransport/src/protocols/fec/CMakeLists.txt (renamed from libtransport/src/security/CMakeLists.txt)22
-rw-r--r--libtransport/src/protocols/fec/fec.cc838
-rw-r--r--libtransport/src/protocols/fec/fec.h (renamed from libtransport/src/core/fec.h)14
-rw-r--r--libtransport/src/protocols/fec/fec_info.h62
-rw-r--r--libtransport/src/protocols/fec/rely.cc205
-rw-r--r--libtransport/src/protocols/fec/rely.h191
-rw-r--r--libtransport/src/protocols/fec/rs.cc418
-rw-r--r--libtransport/src/protocols/fec/rs.h (renamed from libtransport/src/core/rs.h)121
-rw-r--r--libtransport/src/protocols/fec_base.cc (renamed from libtransport/src/interfaces/rtc_socket_producer.cc)19
-rw-r--r--libtransport/src/protocols/fec_base.h85
-rw-r--r--libtransport/src/protocols/fec_utils.h155
-rw-r--r--libtransport/src/protocols/incremental_indexer.h138
-rw-r--r--libtransport/src/protocols/incremental_indexer_bytestream.cc (renamed from libtransport/src/protocols/incremental_indexer.cc)23
-rw-r--r--libtransport/src/protocols/incremental_indexer_bytestream.h119
-rw-r--r--libtransport/src/protocols/index_manager_bytestream.cc72
-rw-r--r--libtransport/src/protocols/index_manager_bytestream.h91
-rw-r--r--libtransport/src/protocols/indexer.cc60
-rw-r--r--libtransport/src/protocols/indexer.h91
-rw-r--r--libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc (renamed from libtransport/src/protocols/manifest_incremental_indexer.cc)95
-rw-r--r--libtransport/src/protocols/manifest_incremental_indexer_bytestream.h (renamed from libtransport/src/protocols/manifest_incremental_indexer.h)27
-rw-r--r--libtransport/src/protocols/packet_manager.h65
-rw-r--r--libtransport/src/protocols/prod_protocol_bytestream.cc74
-rw-r--r--libtransport/src/protocols/prod_protocol_rtc.cc230
-rw-r--r--libtransport/src/protocols/prod_protocol_rtc.h27
-rw-r--r--libtransport/src/protocols/production_protocol.cc7
-rw-r--r--libtransport/src/protocols/production_protocol.h29
-rw-r--r--libtransport/src/protocols/protocol.cc137
-rw-r--r--libtransport/src/protocols/protocol.h114
-rw-r--r--libtransport/src/protocols/raaqm.cc180
-rw-r--r--libtransport/src/protocols/raaqm.h38
-rw-r--r--libtransport/src/protocols/rate_estimation.cc6
-rw-r--r--libtransport/src/protocols/reassembly.cc2
-rw-r--r--libtransport/src/protocols/reassembly.h33
-rw-r--r--libtransport/src/protocols/rtc.cc984
-rw-r--r--libtransport/src/protocols/rtc.h228
-rw-r--r--libtransport/src/protocols/rtc/CMakeLists.txt20
-rw-r--r--libtransport/src/protocols/rtc/congestion_detection.cc101
-rw-r--r--libtransport/src/protocols/rtc/congestion_detection.h138
-rw-r--r--libtransport/src/protocols/rtc/probe_handler.cc2
-rw-r--r--libtransport/src/protocols/rtc/probe_handler.h10
-rw-r--r--libtransport/src/protocols/rtc/rtc.cc466
-rw-r--r--libtransport/src/protocols/rtc/rtc.h46
-rw-r--r--libtransport/src/protocols/rtc/rtc_consts.h35
-rw-r--r--libtransport/src/protocols/rtc/rtc_data_path.cc6
-rw-r--r--libtransport/src/protocols/rtc/rtc_indexer.h195
-rw-r--r--libtransport/src/protocols/rtc/rtc_ldr.cc212
-rw-r--r--libtransport/src/protocols/rtc/rtc_ldr.h26
-rw-r--r--libtransport/src/protocols/rtc/rtc_packet.h2
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_frame.cc79
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_frame.h46
-rw-r--r--libtransport/src/protocols/rtc/rtc_rc_queue.cc6
-rw-r--r--libtransport/src/protocols/rtc/rtc_reassembly.h46
-rw-r--r--libtransport/src/protocols/rtc/rtc_state.cc152
-rw-r--r--libtransport/src/protocols/rtc/rtc_state.h62
-rw-r--r--libtransport/src/protocols/rtc/trendline_estimator.cc334
-rw-r--r--libtransport/src/protocols/rtc/trendline_estimator.h147
-rw-r--r--libtransport/src/protocols/rtc_data_path.cc156
-rw-r--r--libtransport/src/protocols/rtc_data_path.h80
-rw-r--r--libtransport/src/protocols/transport_protocol.cc102
-rw-r--r--libtransport/src/protocols/transport_protocol.h74
-rw-r--r--libtransport/src/protocols/verification_manager.cc101
-rw-r--r--libtransport/src/protocols/verification_manager.h71
-rw-r--r--libtransport/src/security/identity.cc115
-rw-r--r--libtransport/src/security/signer.cc185
-rw-r--r--libtransport/src/security/verifier.cc251
-rw-r--r--libtransport/src/test/CMakeLists.txt55
-rw-r--r--libtransport/src/test/fec_reed_solomon.cc154
-rw-r--r--libtransport/src/test/fec_rely.cc156
-rw-r--r--libtransport/src/test/main.cc22
-rw-r--r--libtransport/src/test/test_auth.cc162
-rw-r--r--libtransport/src/test/test_consumer_producer_rtc.cc15
-rw-r--r--libtransport/src/test/test_core_manifest.cc19
-rw-r--r--libtransport/src/test/test_event_thread.cc11
-rw-r--r--libtransport/src/test/test_fec_reedsolomon.cc184
-rw-r--r--libtransport/src/test/test_fec_rely_wrapper.cc232
-rw-r--r--libtransport/src/test/test_indexer.cc322
-rw-r--r--libtransport/src/test/test_interest.cc5
-rw-r--r--libtransport/src/test/test_packet.cc9
-rw-r--r--libtransport/src/test/test_transport_producer.cc66
-rw-r--r--libtransport/src/transport.config52
-rw-r--r--libtransport/src/utils/CMakeLists.txt2
-rw-r--r--libtransport/src/utils/content_store.cc20
-rw-r--r--libtransport/src/utils/content_store.h4
-rw-r--r--libtransport/src/utils/daemonizator.cc4
-rw-r--r--libtransport/src/utils/epoll_event_reactor.cc25
-rw-r--r--libtransport/src/utils/fd_deadline_timer.h3
-rw-r--r--libtransport/src/utils/log.cc1450
-rw-r--r--libtransport/src/utils/min_filter.h11
-rw-r--r--libtransport/src/utils/suffix_strategy.h31
182 files changed, 6245 insertions, 11453 deletions
diff --git a/libtransport/src/CMakeLists.txt b/libtransport/src/CMakeLists.txt
index 079427fea..5e0cd38e7 100644
--- a/libtransport/src/CMakeLists.txt
+++ b/libtransport/src/CMakeLists.txt
@@ -11,8 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
include(GNUInstallDirs)
set(ASIO_STANDALONE 1)
@@ -31,17 +29,16 @@ configure_file("config.h.in" "hicn/transport/config.h" @ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/hicn/transport/config.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hicn/transport
- COMPONENT lib${LIBTRANSPORT}-dev
+ COMPONENT ${LIBTRANSPORT_COMPONENT}-dev
)
install(
FILES "transport.config"
DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
- COMPONENT lib${LIBTRANSPORT}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
)
list(APPEND COMPILER_DEFINITIONS
- "-DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_${TRANSPORT_LOG_LEVEL}"
"-DASIO_STANDALONE"
)
@@ -67,42 +64,32 @@ endif ()
if (${CMAKE_SYSTEM_NAME} MATCHES "Android")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm")
- add_subdirectory(io_modules)
endif()
-if (DISABLE_SHARED_LIBRARIES)
- build_library(${LIBTRANSPORT}
- STATIC
- SOURCES ${SOURCE_FILES} ${HEADER_FILES}
- INSTALL_HEADERS ${LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES}
- LINK_LIBRARIES ${LIBRARIES}
- DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- HEADER_ROOT_DIR hicn/transport
- DEFINITIONS ${COMPILER_DEFINITIONS}
- VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
- )
-else ()
- build_library(${LIBTRANSPORT}
- STATIC SHARED
- SOURCES ${SOURCE_FILES} ${HEADER_FILES}
- INSTALL_HEADERS ${LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES}
- LINK_LIBRARIES ${LIBRARIES}
- DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- HEADER_ROOT_DIR hicn/transport
- DEFINITIONS ${COMPILER_DEFINITIONS}
- VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
- )
-endif ()
+set (BUILD_TYPES "STATIC")
-# io modules
-if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Android")
- add_subdirectory(io_modules)
+if (NOT DISABLE_SHARED_LIBRARIES)
+ list(APPEND BUILD_TYPES
+ "SHARED"
+ )
endif()
+add_subdirectory(io_modules)
+
+build_library(${LIBTRANSPORT}
+ ${BUILD_TYPES}
+ SOURCES ${SOURCE_FILES} ${HEADER_FILES}
+ INSTALL_HEADERS ${LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES}
+ LINK_LIBRARIES ${LIBRARIES}
+ OBJECT_LIBRARIES ${THIRD_PARTY_OBJECT_LIBRARIES}
+ DEPENDS ${DEPENDENCIES}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ HEADER_ROOT_DIR hicn/transport
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
+)
+
if (${BUILD_TESTS})
add_subdirectory(test)
endif()
diff --git a/libtransport/src/auth/CMakeLists.txt b/libtransport/src/auth/CMakeLists.txt
index 0e7b5832b..699bc1050 100644
--- a/libtransport/src/auth/CMakeLists.txt
+++ b/libtransport/src/auth/CMakeLists.txt
@@ -11,12 +11,12 @@
# 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}/signer.cc
${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.cc
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/auth/crypto_hash.cc b/libtransport/src/auth/crypto_hash.cc
new file mode 100644
index 000000000..b4b0a8b81
--- /dev/null
+++ b/libtransport/src/auth/crypto_hash.cc
@@ -0,0 +1,201 @@
+/*
+ * 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/auth/crypto_hash.h>
+
+using namespace std;
+
+namespace transport {
+namespace auth {
+
+CryptoHash::CryptoHash() : CryptoHash(CryptoHashType::UNKNOWN) {}
+
+CryptoHash::CryptoHash(const CryptoHash &other)
+ : digest_type_(other.digest_type_),
+ digest_(other.digest_),
+ digest_size_(other.digest_size_) {}
+
+CryptoHash::CryptoHash(CryptoHash &&other)
+ : digest_type_(move(other.digest_type_)),
+ digest_(other.digest_),
+ digest_size_(other.digest_size_) {
+ other.reset();
+}
+
+CryptoHash::CryptoHash(CryptoHashType hash_type) { setType(hash_type); }
+
+CryptoHash::CryptoHash(const uint8_t *hash, size_t size,
+ CryptoHashType hash_type)
+ : digest_type_(hash_type), digest_size_(size) {
+ digest_.resize(size);
+ memcpy(digest_.data(), hash, size);
+}
+
+CryptoHash::CryptoHash(const vector<uint8_t> &hash, CryptoHashType hash_type)
+ : CryptoHash(hash.data(), hash.size(), hash_type) {}
+
+CryptoHash &CryptoHash::operator=(const CryptoHash &other) {
+ digest_type_ = other.digest_type_;
+ digest_ = other.digest_;
+ digest_size_ = other.digest_size_;
+ return *this;
+}
+
+bool CryptoHash::operator==(const CryptoHash &other) const {
+ return (digest_type_ == other.digest_type_ && digest_ == other.digest_);
+}
+
+void CryptoHash::computeDigest(const uint8_t *buffer, size_t len) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(digest_type_);
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ EVP_Digest(buffer, len, digest_.data(), (unsigned int *)&digest_size_,
+ (*hash_evp)(), nullptr);
+}
+
+void CryptoHash::computeDigest(const vector<uint8_t> &buffer) {
+ computeDigest(buffer.data(), buffer.size());
+}
+
+void CryptoHash::computeDigest(const utils::MemBuf *buffer) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(digest_type_);
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ EVP_MD_CTX *mcdtx = EVP_MD_CTX_new();
+ const utils::MemBuf *p = buffer;
+
+ if (EVP_DigestInit_ex(mcdtx, (*hash_evp)(), nullptr) == 0) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
+
+ do {
+ if (EVP_DigestUpdate(mcdtx, p->data(), p->length()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
+
+ p = p->next();
+ } while (p != buffer);
+
+ if (EVP_DigestFinal_ex(mcdtx, digest_.data(),
+ (unsigned int *)&digest_size_) != 1) {
+ throw errors::RuntimeException("Digest computation failed");
+ }
+
+ EVP_MD_CTX_free(mcdtx);
+}
+
+vector<uint8_t> CryptoHash::getDigest() const { return digest_; }
+
+string CryptoHash::getStringDigest() const {
+ stringstream string_digest;
+
+ string_digest << hex << setfill('0');
+
+ for (auto byte : digest_) {
+ string_digest << hex << setw(2) << static_cast<int>(byte);
+ }
+
+ return string_digest.str();
+}
+
+CryptoHashType CryptoHash::getType() const { return digest_type_; }
+
+size_t CryptoHash::getSize() const { return digest_size_; }
+
+void CryptoHash::setType(CryptoHashType hash_type) {
+ reset();
+ digest_type_ = hash_type;
+ digest_size_ = CryptoHash::getSize(hash_type);
+ digest_.resize(digest_size_);
+}
+
+void CryptoHash::display() {
+ switch (digest_type_) {
+ case CryptoHashType::SHA256:
+ cout << "SHA256";
+ break;
+ case CryptoHashType::SHA512:
+ cout << "SHA512";
+ break;
+ case CryptoHashType::BLAKE2S256:
+ cout << "BLAKE2s256";
+ break;
+ case CryptoHashType::BLAKE2B512:
+ cout << "BLAKE2b512";
+ break;
+ default:
+ cout << "UNKNOWN";
+ break;
+ }
+
+ cout << ": " << getStringDigest() << endl;
+}
+
+void CryptoHash::reset() {
+ digest_type_ = CryptoHashType::UNKNOWN;
+ digest_.clear();
+ digest_size_ = 0;
+}
+
+CryptoHashEVP CryptoHash::getEVP(CryptoHashType hash_type) {
+ switch (hash_type) {
+ case CryptoHashType::SHA256:
+ return &EVP_sha256;
+ break;
+ case CryptoHashType::SHA512:
+ return &EVP_sha512;
+ break;
+ case CryptoHashType::BLAKE2S256:
+ return &EVP_blake2s256;
+ break;
+ case CryptoHashType::BLAKE2B512:
+ return &EVP_blake2b512;
+ break;
+ default:
+ return nullptr;
+ break;
+ }
+}
+
+size_t CryptoHash::getSize(CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
+
+ if (hash_evp == nullptr) {
+ return 0;
+ }
+
+ return EVP_MD_size((*hash_evp)());
+}
+
+bool CryptoHash::compareDigest(const uint8_t *digest1, const uint8_t *digest2,
+ CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
+
+ if (hash_evp == nullptr) {
+ return false;
+ }
+
+ return !static_cast<bool>(
+ memcmp(digest1, digest2, CryptoHash::getSize(hash_type)));
+}
+
+} // namespace auth
+} // namespace transport
diff --git a/libtransport/src/auth/crypto_suite.cc b/libtransport/src/auth/crypto_suite.cc
new file mode 100644
index 000000000..7e898ef09
--- /dev/null
+++ b/libtransport/src/auth/crypto_suite.cc
@@ -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.
+ */
+
+#include <hicn/transport/auth/crypto_suite.h>
+
+namespace transport {
+namespace auth {
+
+CryptoSuite getSuite(int nid) {
+ switch (nid) {
+ case NID_ecdsa_with_SHA256:
+ return CryptoSuite::ECDSA_SHA256;
+ break;
+ case NID_ecdsa_with_SHA512:
+ return CryptoSuite::ECDSA_SHA512;
+ break;
+ case NID_sha256WithRSAEncryption:
+ return CryptoSuite::RSA_SHA256;
+ break;
+ case NID_sha512WithRSAEncryption:
+ return CryptoSuite::RSA_SHA512;
+ break;
+ case NID_hmacWithSHA256:
+ return CryptoSuite::HMAC_SHA256;
+ break;
+ case NID_hmacWithSHA512:
+ return CryptoSuite::HMAC_SHA512;
+ break;
+ case NID_dsa_with_SHA256:
+ return CryptoSuite::DSA_SHA256;
+ break;
+ case NID_dsa_with_SHA512:
+ return CryptoSuite::DSA_SHA512;
+ break;
+ default:
+ return CryptoSuite::UNKNOWN;
+ break;
+ }
+}
+
+CryptoHashType getHashType(CryptoSuite suite) {
+ switch (suite) {
+ case CryptoSuite::ECDSA_BLAKE2B512:
+ case CryptoSuite::RSA_BLAKE2B512:
+ case CryptoSuite::HMAC_BLAKE2B512:
+ case CryptoSuite::DSA_BLAKE2B512:
+ return CryptoHashType::BLAKE2B512;
+ case CryptoSuite::ECDSA_BLAKE2S256:
+ case CryptoSuite::RSA_BLAKE2S256:
+ case CryptoSuite::HMAC_BLAKE2S256:
+ case CryptoSuite::DSA_BLAKE2S256:
+ return CryptoHashType::BLAKE2S256;
+ case CryptoSuite::ECDSA_SHA256:
+ case CryptoSuite::RSA_SHA256:
+ case CryptoSuite::HMAC_SHA256:
+ case CryptoSuite::DSA_SHA256:
+ return CryptoHashType::SHA256;
+ case CryptoSuite::ECDSA_SHA512:
+ case CryptoSuite::RSA_SHA512:
+ case CryptoSuite::HMAC_SHA512:
+ case CryptoSuite::DSA_SHA512:
+ return CryptoHashType::SHA512;
+ default:
+ return CryptoHashType::UNKNOWN;
+ }
+}
+
+} // namespace auth
+} // namespace transport
diff --git a/libtransport/src/auth/identity.cc b/libtransport/src/auth/identity.cc
index bd787b9b6..f56532033 100644
--- a/libtransport/src/auth/identity.cc
+++ b/libtransport/src/auth/identity.cc
@@ -17,90 +17,262 @@
using namespace std;
+// function needed to create the a certificate
+static bool _addRandomSerial(X509 *cert) {
+ unsigned long serial = 0;
+ unsigned char serial_bytes[sizeof(serial)];
+
+ // Construct random positive serial number.
+ RAND_bytes(serial_bytes, sizeof(serial_bytes));
+ serial_bytes[0] &= 0x7F;
+ serial = 0;
+ for (size_t i = 0; i < sizeof(serial_bytes); i++) {
+ serial = (256 * serial) + serial_bytes[i];
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
+ return true;
+}
+
+static bool _addValidityPeriod(X509 *cert, size_t validityDays) {
+ // Set the validity from now for the specified number of days.
+ X509_gmtime_adj(X509_get_notBefore(cert), (long)0);
+ X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validityDays));
+ return true;
+}
+
+static bool _addSubjectName(X509 *cert, const char *subjectname) {
+ // Set up the simple subject name and issuer name for the certificate.
+ X509_NAME *name = X509_get_subject_name(cert);
+
+ if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+ (unsigned char *)subjectname, -1, -1, 0)) {
+ if (X509_set_issuer_name(cert, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+static bool _addCertificateExtensionWithContext(X509 *cert, int nid,
+ const char *value) {
+ X509_EXTENSION *extension;
+ X509V3_CTX context;
+
+ X509V3_set_ctx_nodb(&context);
+ X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
+ extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+static bool _addCertificateExtension(X509 *cert, int nid, const char *value) {
+ X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool _addExtensions(X509 *cert) {
+ // Add the necessary extensions.
+ if (_addCertificateExtension(cert, NID_basic_constraints,
+ "critical,CA:FALSE") == true) {
+ if (_addCertificateExtension(
+ cert, NID_key_usage,
+ "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,"
+ "keyAgreement") == true) {
+ if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") ==
+ true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+static bool _addKeyIdentifier(X509 *cert) {
+ unsigned char spkid[SHA256_DIGEST_LENGTH];
+ char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
+ if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
+ X509_get_X509_PUBKEY(cert), spkid, NULL)) {
+ for (int i = 0; i < 32; i++) {
+ snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]);
+ }
+ if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) ==
+ true) {
+ if (_addCertificateExtensionWithContext(
+ cert, NID_authority_key_identifier, "keyid:always") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
namespace transport {
namespace auth {
Identity::Identity(const string &keystore_path, const string &keystore_pwd,
CryptoSuite suite, unsigned int signature_len,
unsigned int validity_days, const string &subject_name)
- : identity_(nullptr), signer_(nullptr) {
- parcSecurity_Init();
-
- bool success = parcPkcs12KeyStore_CreateFile(
- keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(),
- parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)),
- signature_len, validity_days);
+ : cert_(X509_new(), ::X509_free) {
+ // create the file and complete it.
+ // first we create the certificate
- parcAssertTrue(
- success,
- "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d, %d) failed.",
- keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(),
- static_cast<int>(suite), static_cast<int>(signature_len), validity_days);
+ // to create the cert we will need a private key
- PARCIdentityFile *identity_file =
- parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str());
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
- identity_ =
- parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+ if (suite == CryptoSuite::RSA_SHA512 || suite == CryptoSuite::RSA_SHA256) {
+ RSA *rsa = RSA_new();
+ BIGNUM *pub_exp;
- PARCSigner *signer = parcIdentity_CreateSigner(
- identity_,
- parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite)));
+ pub_exp = BN_new();
- signer_ = make_shared<AsymmetricSigner>(signer);
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
+ BN_set_word(pub_exp, RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa, signature_len, pub_exp, NULL))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa))
+ throw errors::RuntimeException("can't generate the key");
+ } else if (suite == CryptoSuite::ECDSA_SHA256) {
+ int curve_params;
+ switch (signature_len) {
+ case 160u:
+ curve_params = NID_secp160k1;
+ break;
+ case 192u:
+ curve_params = NID_secp192k1;
+ break;
+ case 224u:
+ curve_params = NID_secp224k1;
+ break;
+ case 256u:
+ curve_params = NID_secp256k1;
+ break;
+ default:
+ curve_params = -1;
+ break;
+ }
+ if (curve_params == -1)
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params);
+ if (ec_key == NULL)
+ throw errors::RuntimeException("can't create ecdsa key from curve");
+ EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_key) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_key) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ } else if (suite == CryptoSuite::DSA_SHA256) {
+ DSA *dsa = DSA_new();
+ unsigned char buffer[32];
+ if (RAND_bytes(buffer, sizeof(buffer)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa, signature_len, buffer, sizeof(buffer),
+ NULL, NULL, NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ }
+ bool success = true;
+ success = success && (X509_set_version(cert_.get(), 2) == 1); // 2 => X509v3
+ success = success && _addRandomSerial(cert_.get());
+ success = success && _addValidityPeriod(cert_.get(), validity_days);
+ success = success && (X509_set_pubkey(cert_.get(), privateKey.get()) == 1);
+ success = success && _addSubjectName(cert_.get(), subject_name.c_str());
+ success = success && _addExtensions(cert_.get());
+ success =
+ success && (X509_sign(cert_.get(), privateKey.get(), EVP_sha256()) != 0);
+ success = success && _addKeyIdentifier(cert_.get());
+ if (!success) {
+ throw errors::RuntimeException("error while creating the certificate");
+ }
+ // the certificate is created. We create the pkcs12 object to write the p12
+ // file
+ PKCS12 *p12 = PKCS12_create(
+ keystore_pwd.c_str(), "ccnxuser", privateKey.get(), cert_.get(), NULL, 0,
+ 0, 0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0);
+ filename_ = keystore_path;
+ int fp = open(filename_.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ if (fp == -1) throw errors::RuntimeException("impossible to create the file");
+ FILE *fp_f = fdopen(fp, "wb");
+ if (fp_f == NULL)
+ throw errors::RuntimeException("impossible to create the file");
+ i2d_PKCS12_fp(fp_f, p12);
+ fclose(fp_f);
+ close(fp);
+ std::shared_ptr<EVP_PKEY> publickey(X509_get_pubkey(cert_.get()),
+ EVP_PKEY_free);
+ signer_ = std::shared_ptr<AsymmetricSigner>(
+ new AsymmetricSigner(suite, privateKey, publickey));
+ signer_->signature_len_ = signature_len;
}
Identity::Identity(string &keystore_path, string &keystore_pwd,
CryptoHashType hash_type)
- : identity_(nullptr), signer_(nullptr) {
- parcSecurity_Init();
-
- PARCIdentityFile *identity_file =
- parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str());
-
- identity_ =
- parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
-
- PARCSigner *signer = parcIdentity_CreateSigner(
- identity_, static_cast<PARCCryptoHashType>(hash_type));
-
- signer_ = make_shared<AsymmetricSigner>(signer);
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
+ : cert_(X509_new(), ::X509_free) {
+ filename_ = keystore_path;
+ pwd_ = keystore_path;
+ // get the key and certificate by first opening the keystore file
+ FILE *p12file = fopen(keystore_path.c_str(), "r");
+ if (p12file == NULL)
+ throw errors::RuntimeException("impossible open keystore");
+ PKCS12 *p12 = d2i_PKCS12_fp(p12file, NULL);
+ EVP_PKEY *privatekey;
+ EVP_PKEY *publickey;
+ X509 *cert = cert_.get();
+ // now we parse the file to get the first key and certificate
+ if (1 != PKCS12_parse(p12, keystore_pwd.c_str(), &privatekey, &cert, NULL))
+ throw errors::RuntimeException("impossible to get the private key");
+ publickey = X509_get_pubkey(cert);
+ // to have the cryptosuite we use the nid number that is used to identify the
+ // suite.
+ CryptoSuite suite = getSuite(X509_get_signature_nid(cert));
+ signer_ = std::shared_ptr<AsymmetricSigner>(new AsymmetricSigner(
+ suite, std::shared_ptr<EVP_PKEY>(privatekey, EVP_PKEY_free),
+ std::shared_ptr<EVP_PKEY>(publickey, EVP_PKEY_free)));
+ PKCS12_free(p12);
}
-Identity::Identity(const Identity &other)
- : identity_(nullptr), signer_(other.signer_) {
- parcSecurity_Init();
- identity_ = parcIdentity_Acquire(other.identity_);
+Identity::Identity(const Identity &other) {
+ pwd_ = other.pwd_;
+ filename_ = other.filename_;
+ signer_ = other.signer_;
+ cert_ = other.cert_;
}
-Identity::Identity(Identity &&other)
- : identity_(nullptr), signer_(move(other.signer_)) {
- parcSecurity_Init();
- identity_ = parcIdentity_Acquire(other.identity_);
- parcIdentity_Release(&other.identity_);
+Identity::Identity(Identity &&other) {
+ signer_ = std::move(other.signer_);
+ other.signer_.reset();
+ cert_ = std::move(other.cert_);
+ other.cert_.reset();
+ pwd_ = other.pwd_;
+ other.pwd_ = "";
+ filename_ = other.filename_;
+ other.filename_ = "";
+ signer_ = other.signer_;
+ other.signer_ = nullptr;
}
-Identity::~Identity() {
- if (identity_) parcIdentity_Release(&identity_);
- parcSecurity_Fini();
-}
+Identity::~Identity() {}
shared_ptr<AsymmetricSigner> Identity::getSigner() const { return signer_; }
-string Identity::getFilename() const {
- return string(parcIdentity_GetFileName(identity_));
-}
+string Identity::getFilename() const { return filename_; }
-string Identity::getPassword() const {
- return string(parcIdentity_GetPassWord(identity_));
+std::shared_ptr<X509> Identity::getCertificate() const { return cert_; }
+std::shared_ptr<EVP_PKEY> Identity::getPrivateKey() const {
+ return signer_->key_;
}
+string Identity::getPassword() const { return pwd_; }
+
Identity Identity::generateIdentity(const string &subject_name) {
string keystore_name = "keystore";
string keystore_password = "password";
diff --git a/libtransport/src/auth/signer.cc b/libtransport/src/auth/signer.cc
index 99c3d099d..884e850ca 100644
--- a/libtransport/src/auth/signer.cc
+++ b/libtransport/src/auth/signer.cc
@@ -15,193 +15,214 @@
#include <hicn/transport/auth/signer.h>
-extern "C" {
-#ifndef _WIN32
-TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
-#endif
-#include <hicn/hicn.h>
-}
-
-#include <chrono>
-
-#define ALLOW_UNALIGNED_READS 1
-
using namespace std;
namespace transport {
namespace auth {
-Signer::Signer() : signer_(nullptr), key_id_(nullptr) { parcSecurity_Init(); }
+// ---------------------------------------------------------
+// Base Signer
+// ---------------------------------------------------------
+Signer::Signer()
+ : suite_(CryptoSuite::UNKNOWN), signature_len_(0), key_(nullptr) {}
-Signer::Signer(PARCSigner *signer) : Signer() { setSigner(signer); }
-
-Signer::~Signer() {
- if (signer_) parcSigner_Release(&signer_);
- if (key_id_) parcKeyId_Release(&key_id_);
- parcSecurity_Fini();
-}
+Signer::~Signer() {}
void Signer::signPacket(PacketPtr packet) {
- parcAssertNotNull(signer_, "Expected non-null signer");
-
- const utils::MemBuf &header_chain = *packet;
+ assert(key_ != nullptr);
core::Packet::Format format = packet->getFormat();
- auto suite = getCryptoSuite();
- size_t signature_len = getSignatureSize();
if (!packet->authenticationHeader()) {
throw errors::MalformedAHPacketException();
}
- packet->setSignatureSize(signature_len);
+ // Set signature size
+ size_t signature_field_len = getSignatureFieldSize();
+ packet->setSignatureSize(signature_field_len);
+ packet->setSignatureSizeGap(0u);
// Copy IP+TCP / ICMP header before zeroing them
hicn_header_t header_copy;
hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
- packet->resetForHash();
- // Fill in the HICN_AH header
+ // Fill in the hICN AH header
auto now = chrono::duration_cast<chrono::milliseconds>(
chrono::system_clock::now().time_since_epoch())
.count();
packet->setSignatureTimestamp(now);
- packet->setValidationAlgorithm(suite);
+ packet->setValidationAlgorithm(suite_);
- // Set the key ID
- KeyId key_id;
- key_id.first = static_cast<uint8_t *>(
- parcBuffer_Overlay((PARCBuffer *)parcKeyId_GetKeyId(key_id_), 0));
- packet->setKeyId(key_id);
+ // Set key ID
+ vector<uint8_t> key_id = key_id_.getDigest();
+ packet->setKeyId({key_id.data(), key_id.size()});
- // Calculate hash
- CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_));
- const utils::MemBuf *current = &header_chain;
+ // Reset fields to compute the packet hash
+ packet->resetForHash();
- hasher.init();
+ // Compute the signature and put it in the packet
+ signBuffer(packet);
+ hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
- do {
- hasher.updateBytes(current->data(), current->length());
- current = current->next();
- } while (current != &header_chain);
+ // Set the gap between the signature field size and the signature real size.
+ packet->setSignatureSizeGap(signature_field_len - signature_len_);
+ memcpy(packet->getSignature(), signature_.data(), signature_len_);
+}
- CryptoHash hash = hasher.finalize();
+void Signer::signBuffer(const std::vector<uint8_t> &buffer) {
+ assert(key_ != nullptr);
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType());
- // Compute signature
- PARCSignature *signature = parcSigner_SignDigestNoAlloc(
- signer_, hash.hash_, packet->getSignature(), (uint32_t)signature_len);
- PARCBuffer *buffer = parcSignature_GetSignature(signature);
- size_t bytes_len = parcBuffer_Remaining(buffer);
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
- if (bytes_len > signature_len) {
- throw errors::MalformedAHPacketException();
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
}
- // Put signature in AH header
- hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
+ if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
- // Release allocated objects
- parcSignature_Release(&signature);
-}
+ if (EVP_DigestSignUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
-void Signer::setSigner(PARCSigner *signer) {
- parcAssertNotNull(signer, "Expected non-null signer");
+ if (EVP_DigestSignFinal(mdctx.get(), nullptr, &signature_len_) != 1) {
+ throw errors::RuntimeException("Digest computation failed");
+ }
- if (signer_) parcSigner_Release(&signer_);
- if (key_id_) parcKeyId_Release(&key_id_);
+ signature_.resize(signature_len_);
- signer_ = parcSigner_Acquire(signer);
- key_id_ = parcSigner_CreateKeyId(signer_);
-}
+ if (EVP_DigestSignFinal(mdctx.get(), signature_.data(), &signature_len_) !=
+ 1) {
+ throw errors::RuntimeException("Digest computation failed");
+ }
-size_t Signer::getSignatureSize() const {
- parcAssertNotNull(signer_, "Expected non-null signer");
- return parcSigner_GetSignatureSize(signer_);
+ signature_.resize(signature_len_);
}
-CryptoSuite Signer::getCryptoSuite() const {
- parcAssertNotNull(signer_, "Expected non-null signer");
- return static_cast<CryptoSuite>(parcSigner_GetCryptoSuite(signer_));
-}
+void Signer::signBuffer(const utils::MemBuf *buffer) {
+ assert(key_ != nullptr);
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType());
-CryptoHashType Signer::getCryptoHashType() const {
- parcAssertNotNull(signer_, "Expected non-null signer");
- return static_cast<CryptoHashType>(parcSigner_GetCryptoHashType(signer_));
-}
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
-PARCSigner *Signer::getParcSigner() const { return signer_; }
+ const utils::MemBuf *p = buffer;
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
-PARCKeyStore *Signer::getParcKeyStore() const {
- parcAssertNotNull(signer_, "Expected non-null signer");
- return parcSigner_GetKeyStore(signer_);
-}
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
+ }
+
+ if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
+
+ do {
+ if (EVP_DigestSignUpdate(mdctx.get(), p->data(), p->length()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
-AsymmetricSigner::AsymmetricSigner(CryptoSuite suite, PARCKeyStore *key_store) {
- parcAssertNotNull(key_store, "Expected non-null key_store");
+ p = p->next();
+ } while (p != buffer);
- auto crypto_suite = static_cast<PARCCryptoSuite>(suite);
+ if (EVP_DigestSignFinal(mdctx.get(), nullptr, &signature_len_) != 1) {
+ throw errors::RuntimeException("Digest computation failed");
+ }
+
+ signature_.resize(signature_len_);
- switch (suite) {
- case CryptoSuite::DSA_SHA256:
- case CryptoSuite::RSA_SHA256:
- case CryptoSuite::RSA_SHA512:
- case CryptoSuite::ECDSA_256K1:
- break;
- default:
- throw errors::RuntimeException(
- "Invalid crypto suite for asymmetric signer");
+ if (EVP_DigestSignFinal(mdctx.get(), signature_.data(), &signature_len_) !=
+ 1) {
+ throw errors::RuntimeException("Digest computation failed");
}
- setSigner(
- parcSigner_Create(parcPublicKeySigner_Create(key_store, crypto_suite),
- PARCPublicKeySignerAsSigner));
+ signature_.resize(signature_len_);
}
-SymmetricSigner::SymmetricSigner(CryptoSuite suite, PARCKeyStore *key_store) {
- parcAssertNotNull(key_store, "Expected non-null key_store");
+vector<uint8_t> Signer::getSignature() const { return signature_; }
- auto crypto_suite = static_cast<PARCCryptoSuite>(suite);
+size_t Signer::getSignatureSize() const { return signature_len_; }
- switch (suite) {
- case CryptoSuite::HMAC_SHA256:
- case CryptoSuite::HMAC_SHA512:
- break;
- default:
- throw errors::RuntimeException(
- "Invalid crypto suite for symmetric signer");
+size_t Signer::getSignatureFieldSize() const {
+ if (signature_len_ % 4 == 0) {
+ return signature_len_;
}
- setSigner(parcSigner_Create(parcSymmetricKeySigner_Create(
- (PARCSymmetricKeyStore *)key_store,
- parcCryptoSuite_GetCryptoHash(crypto_suite)),
- PARCSymmetricKeySignerAsSigner));
+ return (signature_len_ + 4) - (signature_len_ % 4);
}
-SymmetricSigner::SymmetricSigner(CryptoSuite suite, const string &passphrase) {
- auto crypto_suite = static_cast<PARCCryptoSuite>(suite);
-
- switch (suite) {
- case CryptoSuite::HMAC_SHA256:
- case CryptoSuite::HMAC_SHA512:
- break;
- default:
- throw errors::RuntimeException(
- "Invalid crypto suite for symmetric signer");
- }
+CryptoHashType Signer::getHashType() const {
+ return ::transport::auth::getHashType(suite_);
+}
+
+CryptoSuite Signer::getSuite() const { return suite_; }
- PARCBufferComposer *composer = parcBufferComposer_Create();
- parcBufferComposer_PutString(composer, passphrase.c_str());
- PARCBuffer *key_buf = parcBufferComposer_ProduceBuffer(composer);
- parcBufferComposer_Release(&composer);
+// ---------------------------------------------------------
+// Void Signer
+// ---------------------------------------------------------
+void VoidSigner::signPacket(PacketPtr packet){};
- PARCSymmetricKeyStore *key_store = parcSymmetricKeyStore_Create(key_buf);
- PARCSymmetricKeySigner *key_signer = parcSymmetricKeySigner_Create(
- key_store, parcCryptoSuite_GetCryptoHash(crypto_suite));
+void VoidSigner::signBuffer(const std::vector<uint8_t> &buffer){};
- setSigner(parcSigner_Create(key_signer, PARCSymmetricKeySignerAsSigner));
+void VoidSigner::signBuffer(const utils::MemBuf *buffer){};
+
+// ---------------------------------------------------------
+// Asymmetric Signer
+// ---------------------------------------------------------
+AsymmetricSigner::AsymmetricSigner(CryptoSuite suite, shared_ptr<EVP_PKEY> key,
+ shared_ptr<EVP_PKEY> pub_key) {
+ suite_ = suite;
+ key_ = key;
+ key_id_ = CryptoHash(getHashType());
+
+ vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr));
+ uint8_t *pbk_ptr = pbk.data();
+ int len = i2d_PublicKey(pub_key.get(), &pbk_ptr);
+
+ signature_len_ = EVP_PKEY_size(key.get());
+ signature_.resize(signature_len_);
+ key_id_.computeDigest(pbk_ptr, len);
+}
+
+size_t AsymmetricSigner::getSignatureFieldSize() const {
+ size_t field_size = EVP_PKEY_size(key_.get());
+
+ if (field_size % 4 == 0) {
+ return field_size;
+ }
+
+ return (field_size + 4) - (field_size % 4);
+}
+
+// ---------------------------------------------------------
+// Symmetric Signer
+// ---------------------------------------------------------
+SymmetricSigner::SymmetricSigner(CryptoSuite suite, const string &passphrase) {
+ suite_ = suite;
+ key_ = shared_ptr<EVP_PKEY>(
+ EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr,
+ (const unsigned char *)passphrase.c_str(),
+ passphrase.size()),
+ EVP_PKEY_free);
+ key_id_ = CryptoHash(getHashType());
+
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType());
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
- parcSymmetricKeySigner_Release(&key_signer);
- parcSymmetricKeyStore_Release(&key_store);
- parcBuffer_Release(&key_buf);
+ signature_len_ = EVP_MD_size((*hash_evp)());
+ signature_.resize(signature_len_);
+ key_id_.computeDigest((uint8_t *)passphrase.c_str(), passphrase.size());
}
} // namespace auth
diff --git a/libtransport/src/auth/verifier.cc b/libtransport/src/auth/verifier.cc
index c6648a763..c9ac1650f 100644
--- a/libtransport/src/auth/verifier.cc
+++ b/libtransport/src/auth/verifier.cc
@@ -16,168 +16,125 @@
#include <hicn/transport/auth/verifier.h>
#include <protocols/errors.h>
-extern "C" {
-#ifndef _WIN32
-TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
-#endif
-#include <hicn/hicn.h>
-}
-
-#include <sys/stat.h>
-
using namespace std;
namespace transport {
namespace auth {
-const std::vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = {
+const vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = {
VerificationPolicy::DROP,
VerificationPolicy::ABORT,
};
+// ---------------------------------------------------------
+// Base Verifier
+// ---------------------------------------------------------
Verifier::Verifier()
- : hasher_(nullptr),
- verifier_(nullptr),
- verification_failed_cb_(interface::VOID_HANDLER),
- failed_policies_(DEFAULT_FAILED_POLICIES) {
- parcSecurity_Init();
- PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create();
- verifier_ =
- parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier);
- parcInMemoryVerifier_Release(&in_memory_verifier);
-}
+ : verification_failed_cb_(interface::VOID_HANDLER),
+ failed_policies_(DEFAULT_FAILED_POLICIES) {}
-Verifier::~Verifier() {
- if (hasher_) parcCryptoHasher_Release(&hasher_);
- if (verifier_) parcVerifier_Release(&verifier_);
- parcSecurity_Fini();
-}
+Verifier::~Verifier() {}
bool Verifier::verifyPacket(PacketPtr packet) {
- bool valid_packet = false;
core::Packet::Format format = packet->getFormat();
if (!packet->authenticationHeader()) {
throw errors::MalformedAHPacketException();
}
- // Get crypto suite and hash type
- auto suite = static_cast<PARCCryptoSuite>(packet->getValidationAlgorithm());
- PARCCryptoHashType hash_type = parcCryptoSuite_GetCryptoHash(suite);
+ // Get crypto suite, hash type, signature length
+ CryptoSuite suite = packet->getValidationAlgorithm();
+ CryptoHashType hash_type = getHashType(suite);
+ size_t signature_len = packet->getSignatureSizeReal();
// Copy IP+TCP / ICMP header before zeroing them
hicn_header_t header_copy;
hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
+ packet->setSignatureSizeGap(0u);
- // Fetch packet signature
+ // Retrieve packet signature
uint8_t *packet_signature = packet->getSignature();
- size_t signature_len = Verifier::getSignatureSize(packet);
vector<uint8_t> signature_raw(packet_signature,
packet_signature + signature_len);
- // Create a signature buffer from the raw packet signature
- PARCBuffer *bits =
- parcBuffer_Wrap(signature_raw.data(), signature_len, 0, signature_len);
- parcBuffer_Rewind(bits);
-
- // If the signature algo is ECDSA, the signature might be shorter than the
- // signature field
- PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite);
- if (algo == PARCSigningAlgorithm_ECDSA) {
- while (parcBuffer_HasRemaining(bits) && parcBuffer_GetUint8(bits) == 0)
- ;
- parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1);
- }
-
- if (!parcBuffer_HasRemaining(bits)) {
- parcBuffer_Release(&bits);
- return false;
- }
-
- // Create a signature object from the signature buffer
- PARCSignature *signature = parcSignature_Create(
- parcCryptoSuite_GetSigningAlgorithm(suite), hash_type, bits);
-
- // Fetch the key to verify the signature
- KeyId key_buffer = packet->getKeyId();
- PARCBuffer *buffer = parcBuffer_Wrap(key_buffer.first, key_buffer.second, 0,
- key_buffer.second);
- PARCKeyId *key_id = parcKeyId_Create(buffer);
-
// Reset fields that are not used to compute signature
packet->resetForHash();
- // Compute the packet hash
- if (!hasher_)
- setHasher(parcVerifier_GetCryptoHasher(verifier_, key_id, hash_type));
- CryptoHash local_hash = computeHash(packet);
-
- // Compare the packet signature to the locally computed one
- valid_packet = parcVerifier_VerifyDigestSignature(
- verifier_, key_id, local_hash.hash_, suite, signature);
+ // Check signatures
+ bool valid_packet = verifyBuffer(static_cast<utils::MemBuf *>(packet),
+ signature_raw, hash_type);
- // Restore the fields that were reset
+ // Restore header
hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
-
- // Release allocated objects
- parcBuffer_Release(&buffer);
- parcKeyId_Release(&key_id);
- parcSignature_Release(&signature);
- parcBuffer_Release(&bits);
+ packet->setSignatureSizeGap(packet->getSignatureSize() - signature_len);
return valid_packet;
}
-vector<VerificationPolicy> Verifier::verifyPackets(
- const vector<PacketPtr> &packets) {
- vector<VerificationPolicy> policies(packets.size(), VerificationPolicy::DROP);
+Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets) {
+ PolicyMap policies;
+
+ for (const auto &packet : packets) {
+ Suffix suffix = packet->getName().getSuffix();
+ VerificationPolicy policy = VerificationPolicy::ABORT;
- for (unsigned int i = 0; i < packets.size(); ++i) {
- if (verifyPacket(packets[i])) {
- policies[i] = VerificationPolicy::ACCEPT;
+ if (verifyPacket(packet)) {
+ policy = VerificationPolicy::ACCEPT;
}
- callVerificationFailedCallback(packets[i], policies[i]);
+ policies[suffix] = policy;
+ callVerificationFailedCallback(packet, policy);
}
return policies;
}
-vector<VerificationPolicy> Verifier::verifyPackets(
- const vector<PacketPtr> &packets,
- const unordered_map<Suffix, HashEntry> &suffix_map) {
- vector<VerificationPolicy> policies(packets.size(),
- VerificationPolicy::UNKNOWN);
+Verifier::PolicyMap Verifier::verifyHashes(const SuffixMap &packet_map,
+ const SuffixMap &suffix_map) {
+ PolicyMap policies;
- for (unsigned int i = 0; i < packets.size(); ++i) {
- uint32_t suffix = packets[i]->getName().getSuffix();
- auto manifest_hash = suffix_map.find(suffix);
+ for (const auto &packet_hash : packet_map) {
+ VerificationPolicy policy = VerificationPolicy::UNKNOWN;
+ auto manifest_hash = suffix_map.find(packet_hash.first);
if (manifest_hash != suffix_map.end()) {
- CryptoHashType hash_type = manifest_hash->second.first;
- CryptoHash packet_hash = packets[i]->computeDigest(hash_type);
-
- if (!CryptoHash::compareBinaryDigest(
- packet_hash.getDigest<uint8_t>().data(),
- manifest_hash->second.second.data(), hash_type)) {
- policies[i] = VerificationPolicy::ABORT;
- } else {
- policies[i] = VerificationPolicy::ACCEPT;
+ policy = VerificationPolicy::ABORT;
+
+ if (packet_hash.second == manifest_hash->second) {
+ policy = VerificationPolicy::ACCEPT;
}
}
- callVerificationFailedCallback(packets[i], policies[i]);
+ policies[packet_hash.first] = policy;
}
return policies;
}
-void Verifier::addKey(PARCKey *key) { parcVerifier_AddKey(verifier_, key); }
+Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets,
+ const SuffixMap &suffix_map) {
+ PolicyMap policies;
+
+ for (const auto &packet : packets) {
+ Suffix suffix = packet->getName().getSuffix();
+ VerificationPolicy policy = VerificationPolicy::UNKNOWN;
+ auto manifest_hash = suffix_map.find(suffix);
+
+ if (manifest_hash != suffix_map.end()) {
+ policy = VerificationPolicy::ABORT;
+ CryptoHashType hash_type = manifest_hash->second.getType();
+ CryptoHash packet_hash = packet->computeDigest(hash_type);
+
+ if (packet_hash == manifest_hash->second) {
+ policy = VerificationPolicy::ACCEPT;
+ }
+ }
-void Verifier::setHasher(PARCCryptoHasher *hasher) {
- parcAssertNotNull(hasher, "Expected non-null hasher");
- if (hasher_) parcCryptoHasher_Release(&hasher_);
- hasher_ = parcCryptoHasher_Acquire(hasher);
+ policies[suffix] = policy;
+ callVerificationFailedCallback(packet, policy);
+ }
+
+ return policies;
}
void Verifier::setVerificationFailedCallback(
@@ -192,27 +149,6 @@ void Verifier::getVerificationFailedCallback(
*verfication_failed_cb = &verification_failed_cb_;
}
-size_t Verifier::getSignatureSize(const PacketPtr packet) {
- return packet->getSignatureSize();
-}
-
-CryptoHash Verifier::computeHash(PacketPtr packet) {
- parcAssertNotNull(hasher_, "Expected non-null hasher");
-
- CryptoHasher crypto_hasher(hasher_);
- const utils::MemBuf &header_chain = *packet;
- const utils::MemBuf *current = &header_chain;
-
- crypto_hasher.init();
-
- do {
- crypto_hasher.updateBytes(current->data(), current->length());
- current = current->next();
- } while (current != &header_chain);
-
- return crypto_hasher.finalize();
-}
-
void Verifier::callVerificationFailedCallback(PacketPtr packet,
VerificationPolicy &policy) {
if (verification_failed_cb_ == interface::VOID_HANDLER) {
@@ -228,107 +164,222 @@ void Verifier::callVerificationFailedCallback(PacketPtr packet,
}
}
+// ---------------------------------------------------------
+// Void Verifier
+// ---------------------------------------------------------
bool VoidVerifier::verifyPacket(PacketPtr packet) { return true; }
-vector<VerificationPolicy> VoidVerifier::verifyPackets(
+bool VoidVerifier::verifyBuffer(const vector<uint8_t> &buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ return true;
+}
+
+bool VoidVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ return true;
+}
+
+Verifier::PolicyMap VoidVerifier::verifyPackets(
const vector<PacketPtr> &packets) {
- return vector<VerificationPolicy>(packets.size(), VerificationPolicy::ACCEPT);
+ PolicyMap policies;
+
+ for (const auto &packet : packets) {
+ policies[packet->getName().getSuffix()] = VerificationPolicy::ACCEPT;
+ }
+
+ return policies;
}
-vector<VerificationPolicy> VoidVerifier::verifyPackets(
- const vector<PacketPtr> &packets,
- const unordered_map<Suffix, HashEntry> &suffix_map) {
- return vector<VerificationPolicy>(packets.size(), VerificationPolicy::ACCEPT);
+Verifier::PolicyMap VoidVerifier::verifyPackets(
+ const vector<PacketPtr> &packets, const SuffixMap &suffix_map) {
+ return verifyPackets(packets);
}
-AsymmetricVerifier::AsymmetricVerifier(PARCKey *pub_key) { addKey(pub_key); }
+// ---------------------------------------------------------
+// Asymmetric Verifier
+// ---------------------------------------------------------
+AsymmetricVerifier::AsymmetricVerifier(shared_ptr<EVP_PKEY> key) {
+ setKey(key);
+}
AsymmetricVerifier::AsymmetricVerifier(const string &cert_path) {
- setCertificate(cert_path);
+ useCertificate(cert_path);
+}
+
+AsymmetricVerifier::AsymmetricVerifier(shared_ptr<X509> cert) {
+ useCertificate(cert);
}
-void AsymmetricVerifier::setCertificate(const string &cert_path) {
- PARCCertificateFactory *factory = parcCertificateFactory_Create(
- PARCCertificateType_X509, PARCContainerEncoding_PEM);
+void AsymmetricVerifier::setKey(shared_ptr<EVP_PKEY> key) { key_ = key; };
- struct stat buffer;
- if (stat(cert_path.c_str(), &buffer) != 0) {
- throw errors::RuntimeException("Certificate does not exist");
+void AsymmetricVerifier::useCertificate(const string &cert_path) {
+ FILE *certf = fopen(cert_path.c_str(), "rb");
+
+ if (certf == nullptr) {
+ throw errors::RuntimeException("Certificate not found");
}
- PARCCertificate *certificate =
- parcCertificateFactory_CreateCertificateFromFile(factory,
- cert_path.c_str(), NULL);
- PARCKey *key = parcCertificate_GetPublicKey(certificate);
+ shared_ptr<X509> cert = shared_ptr<X509>(
+ PEM_read_X509(certf, nullptr, nullptr, nullptr), ::X509_free);
+ useCertificate(cert);
- addKey(key);
+ fclose(certf);
+}
- parcKey_Release(&key);
- parcCertificateFactory_Release(&factory);
+void AsymmetricVerifier::useCertificate(shared_ptr<X509> cert) {
+ key_ = shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
}
-SymmetricVerifier::SymmetricVerifier(const string &passphrase)
- : passphrase_(nullptr), signer_(nullptr) {
- setPassphrase(passphrase);
+bool AsymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
+ }
+
+ if (EVP_DigestVerifyInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
+
+ if (EVP_DigestVerifyUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
+
+ return EVP_DigestVerifyFinal(mdctx.get(), signature.data(),
+ signature.size()) == 1;
+}
+
+bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ const utils::MemBuf *p = buffer;
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
+
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
+ }
+
+ if (EVP_DigestVerifyInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
+
+ do {
+ if (EVP_DigestVerifyUpdate(mdctx.get(), p->data(), p->length()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
+
+ p = p->next();
+ } while (p != buffer);
+
+ return EVP_DigestVerifyFinal(mdctx.get(), signature.data(),
+ signature.size()) == 1;
}
-SymmetricVerifier::~SymmetricVerifier() {
- if (passphrase_) parcBuffer_Release(&passphrase_);
- if (signer_) parcSigner_Release(&signer_);
+// ---------------------------------------------------------
+// Symmetric Verifier
+// ---------------------------------------------------------
+SymmetricVerifier::SymmetricVerifier(const string &passphrase) {
+ setPassphrase(passphrase);
}
+// Create and set a symmetric key from a passphrase.
void SymmetricVerifier::setPassphrase(const string &passphrase) {
- if (passphrase_) parcBuffer_Release(&passphrase_);
-
- PARCBufferComposer *composer = parcBufferComposer_Create();
- parcBufferComposer_PutString(composer, passphrase.c_str());
- passphrase_ = parcBufferComposer_ProduceBuffer(composer);
- parcBufferComposer_Release(&composer);
+ key_ = shared_ptr<EVP_PKEY>(
+ EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr,
+ (const unsigned char *)passphrase.c_str(),
+ passphrase.size()),
+ EVP_PKEY_free);
}
-void SymmetricVerifier::setSigner(const PARCCryptoSuite &suite) {
- parcAssertNotNull(passphrase_, "Expected non-null passphrase");
+bool SymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
- if (signer_) parcSigner_Release(&signer_);
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ vector<uint8_t> signature_bis(signature.size());
+ size_t signature_bis_len;
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
- PARCSymmetricKeyStore *key_store = parcSymmetricKeyStore_Create(passphrase_);
- PARCSymmetricKeySigner *key_signer = parcSymmetricKeySigner_Create(
- key_store, parcCryptoSuite_GetCryptoHash(suite));
- signer_ = parcSigner_Create(key_signer, PARCSymmetricKeySignerAsSigner);
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
+ }
- PARCKeyId *key_id = parcSigner_CreateKeyId(signer_);
- PARCKey *key = parcKey_CreateFromSymmetricKey(
- key_id, parcSigner_GetSigningAlgorithm(signer_), passphrase_);
+ if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
- addKey(key);
- setHasher(parcSigner_GetCryptoHasher(signer_));
+ if (EVP_DigestSignUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
+ }
- parcSymmetricKeyStore_Release(&key_store);
- parcSymmetricKeySigner_Release(&key_signer);
- parcKeyId_Release(&key_id);
- parcKey_Release(&key);
+ if (EVP_DigestSignFinal(mdctx.get(), signature_bis.data(),
+ &signature_bis_len) != 1) {
+ throw errors::RuntimeException("Digest computation failed");
+ }
+
+ return signature == signature_bis && signature.size() == signature_bis_len;
}
-vector<VerificationPolicy> SymmetricVerifier::verifyPackets(
- const vector<PacketPtr> &packets) {
- vector<VerificationPolicy> policies(packets.size(), VerificationPolicy::DROP);
+bool SymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const vector<uint8_t> &signature,
+ CryptoHashType hash_type) {
+ CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type);
+
+ if (hash_evp == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
- for (unsigned int i = 0; i < packets.size(); ++i) {
- auto suite =
- static_cast<PARCCryptoSuite>(packets[i]->getValidationAlgorithm());
+ const utils::MemBuf *p = buffer;
+ vector<uint8_t> signature_bis(signature.size());
+ size_t signature_bis_len;
+ shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free);
- if (!signer_ || suite != parcSigner_GetCryptoSuite(signer_)) {
- setSigner(suite);
- }
+ if (mdctx == nullptr) {
+ throw errors::RuntimeException("Digest context allocation failed");
+ }
- if (verifyPacket(packets[i])) {
- policies[i] = VerificationPolicy::ACCEPT;
+ if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Digest initialization failed");
+ }
+
+ do {
+ if (EVP_DigestSignUpdate(mdctx.get(), p->data(), p->length()) != 1) {
+ throw errors::RuntimeException("Digest update failed");
}
- callVerificationFailedCallback(packets[i], policies[i]);
+ p = p->next();
+ } while (p != buffer);
+
+ if (EVP_DigestSignFinal(mdctx.get(), signature_bis.data(),
+ &signature_bis_len) != 1) {
+ throw errors::RuntimeException("Digest computation failed");
}
- return policies;
+ return signature == signature_bis && signature.size() == signature_bis_len;
}
} // namespace auth
diff --git a/libtransport/src/config.h.in b/libtransport/src/config.h.in
index ef47affda..73a326a84 100644
--- a/libtransport/src/config.h.in
+++ b/libtransport/src/config.h.in
@@ -26,5 +26,6 @@
#endif
#define RAAQM_CONFIG_PATH "@raaqm_config_path@"
+#define ENABLE_RELY @ENABLE_RELY@
#cmakedefine __vpp__
diff --git a/libtransport/src/core/CMakeLists.txt b/libtransport/src/core/CMakeLists.txt
index 4e3ac10ec..e442bb863 100644
--- a/libtransport/src/core/CMakeLists.txt
+++ b/libtransport/src/core/CMakeLists.txt
@@ -11,8 +11,6 @@
# 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}/facade.h
${CMAKE_CURRENT_SOURCE_DIR}/manifest.h
@@ -24,7 +22,6 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/errors.h
${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.h
${CMAKE_CURRENT_SOURCE_DIR}/local_connector.h
- ${CMAKE_CURRENT_SOURCE_DIR}/rs.h
)
list(APPEND SOURCE_FILES
@@ -39,8 +36,6 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc
${CMAKE_CURRENT_SOURCE_DIR}/io_module.cc
${CMAKE_CURRENT_SOURCE_DIR}/local_connector.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/fec.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/rs.cc
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/core/connector.cc b/libtransport/src/core/connector.cc
deleted file mode 100644
index 63919537d..000000000
--- a/libtransport/src/core/connector.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 <core/connector.h>
-
-namespace transport {
-
-namespace core {
-
-std::once_flag Connector::init_flag_;
-
-Connector::Connector(PacketReceivedCallback &&receive_callback,
- OnReconnect &&reconnect_callback)
- : packet_pool_(),
- receive_callback_(std::move(receive_callback)),
- on_reconnect_callback_(std::move(reconnect_callback)),
- state_(ConnectorState::CLOSED) {
- 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/core/connector.h b/libtransport/src/core/connector.h
deleted file mode 100644
index f2bbe5dcd..000000000
--- a/libtransport/src/core/connector.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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,
-};
-
-class Connector {
- protected:
- enum class ConnectorState {
- CLOSED,
- CONNECTING,
- CONNECTED,
- };
-
- public:
- static constexpr std::size_t packet_size = 2048;
- 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()>;
-
- Connector(PacketReceivedCallback &&receive_callback,
- OnReconnect &&reconnect_callback);
-
- virtual ~Connector(){};
-
- 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 ConnectorState state() { return state_; };
-
- virtual bool isConnected() { return state_ == ConnectorState::CONNECTED; }
-
- 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();
- }
-
- if (result.second->isChained()) {
- result.second->separateChain(result.second->next(),
- result.second->prev());
- }
-
- result.second->trimEnd(result.second->length());
- return std::move(result.second);
- }
-
- private:
- void init();
-
- protected:
- static std::once_flag init_flag_;
- utils::ObjectPool<utils::MemBuf> packet_pool_;
- PacketQueue output_buffer_;
-
- // Connector events
- PacketReceivedCallback receive_callback_;
- OnReconnect on_reconnect_callback_;
-
- // Connector state
- ConnectorState state_;
-};
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/core/content_object.cc b/libtransport/src/core/content_object.cc
index 0c68ef559..411494fdf 100644
--- a/libtransport/src/core/content_object.cc
+++ b/libtransport/src/core/content_object.cc
@@ -104,19 +104,6 @@ void ContentObject::setName(const Name &name) {
}
}
-void ContentObject::setName(Name &&name) {
- if (hicn_data_set_name(format_, packet_start_, name.getStructReference()) <
- 0) {
- throw errors::RuntimeException(
- "Error getting the payload length from content object.");
- }
-
- if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
- 0) {
- throw errors::MalformedPacketException();
- }
-}
-
uint32_t ContentObject::getPathLabel() const {
uint32_t path_label;
if (hicn_data_get_path_label(packet_start_, &path_label) < 0) {
diff --git a/libtransport/src/core/fec.cc b/libtransport/src/core/fec.cc
deleted file mode 100644
index 0ce9625a2..000000000
--- a/libtransport/src/core/fec.cc
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * fec.c -- forward error correction based on Vandermonde matrices
- * 980624
- * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
- *
- * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
- * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
- * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-/*
- * The following parameter defines how many bits are used for
- * field elements. The code supports any value from 2 to 16
- * but fastest operation is achieved with 8 bit elements
- * This is the only parameter you may want to change.
- */
-#ifndef GF_BITS
-#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <hicn/transport/portability/platform.h>
-#include "fec.h"
-
-/**
- * XXX This disable a warning raising only in some platforms.
- * TODO Check if this warning is a mistake or it is a real bug:
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83404
- * https://gcc.gnu.org/bugzilla//show_bug.cgi?id=88059
- */
-#ifndef __clang__
-#ifndef _WIN32
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-#endif
-#endif
-
-/*
- * compatibility stuff
- */
-#if defined (MSDOS) || defined (_WIN32) /* but also for others, e.g. sun... */
-#define NEED_BCOPY
-#define bcmp(a,b,n) memcmp(a,b,n)
-#endif
-
-#ifdef ANDROID
-#define bcmp(a,b,n) memcmp(a,b,n)
-#endif
-
-#ifdef NEED_BCOPY
-#define bcopy(s, d, siz) memcpy((d), (s), (siz))
-#define bzero(d, siz) memset((d), '\0', (siz))
-#endif
-
-/*
- * stuff used for testing purposes only
- */
-
-#ifdef TEST
-#define DEB(x)
-#define DDB(x) x
-#define DEBUG 0 /* minimal debugging */
-#ifdef MSDOS
-#include <time.h>
-struct timeval {
- unsigned long ticks;
-};
-#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
-#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
-typedef unsigned long u_long ;
-typedef unsigned short u_short ;
-#else /* typically, unix systems */
-#include <sys/time.h>
-#define DIFF_T(a,b) \
- (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
-#endif
-
-#define TICK(t) \
- {struct timeval x ; \
- gettimeofday(&x, NULL) ; \
- t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
- }
-#define TOCK(t) \
- { u_long t1 ; TICK(t1) ; \
- if (t1 < t) t = 256000000 + t1 - t ; \
- else t = t1 - t ; \
- if (t == 0) t = 1 ;}
-
-u_long ticks[10]; /* vars for timekeeping */
-#else
-#define DEB(x)
-#define DDB(x)
-#define TICK(x)
-#define TOCK(x)
-#endif /* TEST */
-
-/*
- * You should not need to change anything beyond this point.
- * The first part of the file implements linear algebra in GF.
- *
- * gf is the type used to store an element of the Galois Field.
- * Must constain at least GF_BITS bits.
- *
- * Note: unsigned char will work up to GF(256) but int seems to run
- * faster on the Pentium. We use int whenever have to deal with an
- * index, since they are generally faster.
- */
-#if (GF_BITS < 2 && GF_BITS >16)
-#error "GF_BITS must be 2 .. 16"
-#endif
-
-
-#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
-
-/*
- * Primitive polynomials - see Lin & Costello, Appendix A,
- * and Lee & Messerschmitt, p. 453.
- */
-static const char *allPp[] = { /* GF_BITS polynomial */
- NULL, /* 0 no code */
- NULL, /* 1 no code */
- "111", /* 2 1+x+x^2 */
- "1101", /* 3 1+x+x^3 */
- "11001", /* 4 1+x+x^4 */
- "101001", /* 5 1+x^2+x^5 */
- "1100001", /* 6 1+x+x^6 */
- "10010001", /* 7 1 + x^3 + x^7 */
- "101110001", /* 8 1+x^2+x^3+x^4+x^8 */
- "1000100001", /* 9 1+x^4+x^9 */
- "10010000001", /* 10 1+x^3+x^10 */
- "101000000001", /* 11 1+x^2+x^11 */
- "1100101000001", /* 12 1+x+x^4+x^6+x^12 */
- "11011000000001", /* 13 1+x+x^3+x^4+x^13 */
- "110000100010001", /* 14 1+x+x^6+x^10+x^14 */
- "1100000000000001", /* 15 1+x+x^15 */
- "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
-};
-
-
-/*
- * To speed up computations, we have tables for logarithm, exponent
- * and inverse of a number. If GF_BITS <= 8, we use a table for
- * multiplication as well (it takes 64K, no big deal even on a PDA,
- * especially because it can be pre-initialized an put into a ROM!),
- * otherwhise we use a table of logarithms.
- * In any case the macro gf_mul(x,y) takes care of multiplications.
- */
-
-static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */
-static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
-static gf inverse[GF_SIZE+1]; /* inverse of field elem. */
- /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
-
-/*
- * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
- * without a slow divide.
- */
-static inline gf
-modnn(int x)
-{
- while (x >= GF_SIZE) {
- x -= GF_SIZE;
- x = (x >> GF_BITS) + (x & GF_SIZE);
- }
- return x;
-}
-
-#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
-
-/*
- * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
- * faster to use a multiplication table.
- *
- * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
- * many numbers by the same constant. In this case the first
- * call sets the constant, and others perform the multiplications.
- * A value related to the multiplication is held in a local variable
- * declared with USE_GF_MULC . See usage in addmul1().
- */
-#if (GF_BITS <= 8)
-static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
-
-#define gf_mul(x,y) gf_mul_table[x][y]
-
-#define USE_GF_MULC gf * __gf_mulc_
-#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
-#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
-
-static void
-init_mul_table()
-{
- int i, j;
- for (i=0; i< GF_SIZE+1; i++)
- for (j=0; j< GF_SIZE+1; j++)
- gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
-
- for (j=0; j< GF_SIZE+1; j++)
- gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
-}
-#else /* GF_BITS > 8 */
-static inline gf
-gf_mul(x,y)
-{
- if ( (x) == 0 || (y)==0 ) return 0;
-
- return gf_exp[gf_log[x] + gf_log[y] ] ;
-}
-#define init_mul_table()
-
-#define USE_GF_MULC register gf * __gf_mulc_
-#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
-#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
-#endif
-
-/*
- * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
- * Lookup tables:
- * index->polynomial form gf_exp[] contains j= \alpha^i;
- * polynomial form -> index form gf_log[ j = \alpha^i ] = i
- * \alpha=x is the primitive element of GF(2^m)
- *
- * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
- * multiplication of two numbers can be resolved without calling modnn
- */
-
-/*
- * i use malloc so many times, it is easier to put checks all in
- * one place.
- */
-static void *
-my_malloc(int sz, const char *err_string)
-{
- void *p = malloc( sz );
- if (p == NULL) {
- fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
- exit(1) ;
- }
- return p ;
-}
-
-#define NEW_GF_MATRIX(rows, cols) \
- (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
-
-/*
- * initialize the data structures used for computations in GF.
- */
-static void
-generate_gf(void)
-{
- int i;
- gf mask;
- const char *Pp = allPp[GF_BITS] ;
-
- mask = 1; /* x ** 0 = 1 */
- gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
- /*
- * first, generate the (polynomial representation of) powers of \alpha,
- * which are stored in gf_exp[i] = \alpha ** i .
- * At the same time build gf_log[gf_exp[i]] = i .
- * The first GF_BITS powers are simply bits shifted to the left.
- */
- for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
- gf_exp[i] = mask;
- gf_log[gf_exp[i]] = i;
- /*
- * If Pp[i] == 1 then \alpha ** i occurs in poly-repr
- * gf_exp[GF_BITS] = \alpha ** GF_BITS
- */
- if ( Pp[i] == '1' )
- gf_exp[GF_BITS] ^= mask;
- }
- /*
- * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
- * compute its inverse.
- */
- gf_log[gf_exp[GF_BITS]] = GF_BITS;
- /*
- * Poly-repr of \alpha ** (i+1) is given by poly-repr of
- * \alpha ** i shifted left one-bit and accounting for any
- * \alpha ** GF_BITS term that may occur when poly-repr of
- * \alpha ** i is shifted.
- */
- mask = 1 << (GF_BITS - 1 ) ;
- for (i = GF_BITS + 1; i < GF_SIZE; i++) {
- if (gf_exp[i - 1] >= mask)
- gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
- else
- gf_exp[i] = gf_exp[i - 1] << 1;
- gf_log[gf_exp[i]] = i;
- }
- /*
- * log(0) is not defined, so use a special value
- */
- gf_log[0] = GF_SIZE ;
- /* set the extended gf_exp values for fast multiply */
- for (i = 0 ; i < GF_SIZE ; i++)
- gf_exp[i + GF_SIZE] = gf_exp[i] ;
-
- /*
- * again special cases. 0 has no inverse. This used to
- * be initialized to GF_SIZE, but it should make no difference
- * since noone is supposed to read from here.
- */
- inverse[0] = 0 ;
- inverse[1] = 1;
- for (i=2; i<=GF_SIZE; i++)
- inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
-}
-
-/*
- * Various linear algebra operations that i use often.
- */
-
-/*
- * addmul() computes dst[] = dst[] + c * src[]
- * This is used often, so better optimize it! Currently the loop is
- * unrolled 16 times, a good value for 486 and pentium-class machines.
- * The case c=0 is also optimized, whereas c=1 is not. These
- * calls are unfrequent in my typical apps so I did not bother.
- *
- * Note that gcc on
- */
-#define addmul(dst, src, c, sz) \
- if (c != 0) addmul1(dst, src, c, sz)
-
-#define UNROLL 16 /* 1, 4, 8, 16 */
-static void
-addmul1(gf *dst1, gf *src1, gf c, int sz)
-{
- USE_GF_MULC ;
- gf *dst = dst1, *src = src1 ;
- gf *lim = &dst[sz - UNROLL + 1] ;
-
- GF_MULC0(c) ;
-
-#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
- for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
- GF_ADDMULC( dst[0] , src[0] );
- GF_ADDMULC( dst[1] , src[1] );
- GF_ADDMULC( dst[2] , src[2] );
- GF_ADDMULC( dst[3] , src[3] );
-#if (UNROLL > 4)
- GF_ADDMULC( dst[4] , src[4] );
- GF_ADDMULC( dst[5] , src[5] );
- GF_ADDMULC( dst[6] , src[6] );
- GF_ADDMULC( dst[7] , src[7] );
-#endif
-#if (UNROLL > 8)
- GF_ADDMULC( dst[8] , src[8] );
- GF_ADDMULC( dst[9] , src[9] );
- GF_ADDMULC( dst[10] , src[10] );
- GF_ADDMULC( dst[11] , src[11] );
- GF_ADDMULC( dst[12] , src[12] );
- GF_ADDMULC( dst[13] , src[13] );
- GF_ADDMULC( dst[14] , src[14] );
- GF_ADDMULC( dst[15] , src[15] );
-#endif
- }
-#endif
- lim += UNROLL - 1 ;
- for (; dst < lim; dst++, src++ ) /* final components */
- GF_ADDMULC( *dst , *src );
-}
-
-/*
- * computes C = AB where A is n*k, B is k*m, C is n*m
- */
-static void
-matmul(gf *a, gf *b, gf *c, int n, int k, int m)
-{
- int row, col, i ;
-
- for (row = 0; row < n ; row++) {
- for (col = 0; col < m ; col++) {
- gf *pa = &a[ row * k ];
- gf *pb = &b[ col ];
- gf acc = 0 ;
- for (i = 0; i < k ; i++, pa++, pb += m )
- acc ^= gf_mul( *pa, *pb ) ;
- c[ row * m + col ] = acc ;
- }
- }
-}
-
-#ifdef DEBUGG
-/*
- * returns 1 if the square matrix is identiy
- * (only for test)
- */
-static int
-is_identity(gf *m, int k)
-{
- int row, col ;
- for (row=0; row<k; row++)
- for (col=0; col<k; col++)
- if ( (row==col && *m != 1) ||
- (row!=col && *m != 0) )
- return 0 ;
- else
- m++ ;
- return 1 ;
-}
-#endif /* debug */
-
-/*
- * invert_mat() takes a matrix and produces its inverse
- * k is the size of the matrix.
- * (Gauss-Jordan, adapted from Numerical Recipes in C)
- * Return non-zero if singular.
- */
-DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
-static int
-invert_mat(gf *src, int k)
-{
- gf c, *p ;
- int irow, icol, row, col, i, ix ;
-
- int error = 1 ;
- int *indxc = (int*)my_malloc(k*sizeof(int), "indxc");
- int *indxr = (int*)my_malloc(k*sizeof(int), "indxr");
- int *ipiv = (int*)my_malloc(k*sizeof(int), "ipiv");
- gf *id_row = NEW_GF_MATRIX(1, k);
- gf *temp_row = NEW_GF_MATRIX(1, k);
-
- bzero(id_row, k*sizeof(gf));
- DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
- /*
- * ipiv marks elements already used as pivots.
- */
- for (i = 0; i < k ; i++)
- ipiv[i] = 0 ;
-
- for (col = 0; col < k ; col++) {
- gf *pivot_row ;
- /*
- * Zeroing column 'col', look for a non-zero element.
- * First try on the diagonal, if it fails, look elsewhere.
- */
- irow = icol = -1 ;
- if (ipiv[col] != 1 && src[col*k + col] != 0) {
- irow = col ;
- icol = col ;
- goto found_piv ;
- }
- for (row = 0 ; row < k ; row++) {
- if (ipiv[row] != 1) {
- for (ix = 0 ; ix < k ; ix++) {
- DEB( pivloops++ ; )
- if (ipiv[ix] == 0) {
- if (src[row*k + ix] != 0) {
- irow = row ;
- icol = ix ;
- goto found_piv ;
- }
- } else if (ipiv[ix] > 1) {
- fprintf(stderr, "singular matrix\n");
- goto fail ;
- }
- }
- }
- }
- if (icol == -1) {
- fprintf(stderr, "XXX pivot not found!\n");
- goto fail ;
- }
-found_piv:
- ++(ipiv[icol]) ;
- /*
- * swap rows irow and icol, so afterwards the diagonal
- * element will be correct. Rarely done, not worth
- * optimizing.
- */
- if (irow != icol) {
- for (ix = 0 ; ix < k ; ix++ ) {
- SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
- }
- }
- indxr[col] = irow ;
- indxc[col] = icol ;
- pivot_row = &src[icol*k] ;
- c = pivot_row[icol] ;
- if (c == 0) {
- fprintf(stderr, "singular matrix 2\n");
- goto fail ;
- }
- if (c != 1 ) { /* otherwhise this is a NOP */
- /*
- * this is done often , but optimizing is not so
- * fruitful, at least in the obvious ways (unrolling)
- */
- DEB( pivswaps++ ; )
- c = inverse[ c ] ;
- pivot_row[icol] = 1 ;
- for (ix = 0 ; ix < k ; ix++ )
- pivot_row[ix] = gf_mul(c, pivot_row[ix] );
- }
- /*
- * from all rows, remove multiples of the selected row
- * to zero the relevant entry (in fact, the entry is not zero
- * because we know it must be zero).
- * (Here, if we know that the pivot_row is the identity,
- * we can optimize the addmul).
- */
- id_row[icol] = 1;
- if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
- for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
- if (ix != icol) {
- c = p[icol] ;
- p[icol] = 0 ;
- addmul(p, pivot_row, c, k );
- }
- }
- }
- id_row[icol] = 0;
- } /* done all columns */
- for (col = k-1 ; col >= 0 ; col-- ) {
- if (indxr[col] <0 || indxr[col] >= k)
- fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
- else if (indxc[col] <0 || indxc[col] >= k)
- fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
- else
- if (indxr[col] != indxc[col] ) {
- for (row = 0 ; row < k ; row++ ) {
- SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
- }
- }
- }
- error = 0 ;
-fail:
- free(indxc);
- free(indxr);
- free(ipiv);
- free(id_row);
- free(temp_row);
- return error ;
-}
-
-/*
- * fast code for inverting a vandermonde matrix.
- * XXX NOTE: It assumes that the matrix
- * is not singular and _IS_ a vandermonde matrix. Only uses
- * the second column of the matrix, containing the p_i's.
- *
- * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
- * largely revised for my purposes.
- * p = coefficients of the matrix (p_i)
- * q = values of the polynomial (known)
- */
-
-int
-invert_vdm(gf *src, int k)
-{
- int i, j, row, col ;
- gf *b, *c, *p;
- gf t, xx ;
-
- if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
- return 0 ;
- /*
- * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
- * b holds the coefficient for the matrix inversion
- */
- c = NEW_GF_MATRIX(1, k);
- b = NEW_GF_MATRIX(1, k);
-
- p = NEW_GF_MATRIX(1, k);
-
- for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
- c[i] = 0 ;
- p[i] = src[j] ; /* p[i] */
- }
- /*
- * construct coeffs. recursively. We know c[k] = 1 (implicit)
- * and start P_0 = x - p_0, then at each stage multiply by
- * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
- * After k steps we are done.
- */
- c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
- for (i = 1 ; i < k ; i++ ) {
- gf p_i = p[i] ; /* see above comment */
- for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
- c[j] ^= gf_mul( p_i, c[j+1] ) ;
- c[k-1] ^= p_i ;
- }
-
- for (row = 0 ; row < k ; row++ ) {
- /*
- * synthetic division etc.
- */
- xx = p[row] ;
- t = 1 ;
- b[k-1] = 1 ; /* this is in fact c[k] */
- for (i = k-2 ; i >= 0 ; i-- ) {
- b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
- t = gf_mul(xx, t) ^ b[i] ;
- }
- for (col = 0 ; col < k ; col++ )
- src[col*k + row] = gf_mul(inverse[t], b[col] );
- }
- free(c) ;
- free(b) ;
- free(p) ;
- return 0 ;
-}
-
-static int fec_initialized = 0 ;
-static void
-init_fec()
-{
- TICK(ticks[0]);
- generate_gf();
- TOCK(ticks[0]);
- DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
- TICK(ticks[0]);
- init_mul_table();
- TOCK(ticks[0]);
- DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
- fec_initialized = 1 ;
-}
-
-/*
- * This section contains the proper FEC encoding/decoding routines.
- * The encoding matrix is computed starting with a Vandermonde matrix,
- * and then transforming it into a systematic matrix.
- */
-
-#define FEC_MAGIC 0xFECC0DEC
-
-void
-fec_free(struct fec_parms *p)
-{
- if (p==NULL ||
- p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (unsigned long)(p->enc_matrix)) ) {
- fprintf(stderr, "bad parameters to fec_free\n");
- return ;
- }
- free(p->enc_matrix);
- free(p);
-}
-
-/*
- * create a new encoder, returning a descriptor. This contains k,n and
- * the encoding matrix.
- */
-struct fec_parms *
-fec_new(int k, int n)
-{
- int row, col ;
- gf *p, *tmp_m ;
-
- struct fec_parms *retval ;
-
- if (fec_initialized == 0)
- init_fec();
-
- if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
- fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
- k, n, GF_SIZE );
- return NULL ;
- }
- retval = (struct fec_parms *)my_malloc(sizeof(struct fec_parms), "new_code");
- retval->k = k ;
- retval->n = n ;
- retval->enc_matrix = NEW_GF_MATRIX(n, k);
- retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (unsigned long)(retval->enc_matrix) ;
- tmp_m = NEW_GF_MATRIX(n, k);
- /*
- * fill the matrix with powers of field elements, starting from 0.
- * The first row is special, cannot be computed with exp. table.
- */
- tmp_m[0] = 1 ;
- for (col = 1; col < k ; col++)
- tmp_m[col] = 0 ;
- for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
- for ( col = 0 ; col < k ; col ++ )
- p[col] = gf_exp[modnn(row*col)];
- }
-
- /*
- * quick code to build systematic matrix: invert the top
- * k*k vandermonde matrix, multiply right the bottom n-k rows
- * by the inverse, and construct the identity matrix at the top.
- */
- TICK(ticks[3]);
- invert_vdm(tmp_m, k); /* much faster than invert_mat */
- matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
- /*
- * the upper matrix is I so do not bother with a slow multiply
- */
- bzero(retval->enc_matrix, k*k*sizeof(gf) );
- for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
- *p = 1 ;
- free(tmp_m);
- TOCK(ticks[3]);
-
- DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
- ticks[3]);)
- DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
- return retval ;
-}
-
-/*
- * fec_encode accepts as input pointers to n data packets of size sz,
- * and produces as output a packet pointed to by fec, computed
- * with index "index".
- */
-void
-fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
-{
- int i, k = code->k ;
- gf *p ;
-
- if (GF_BITS > 8)
- sz /= 2 ;
-
- if (index < k)
- bcopy(src[index], fec, sz*sizeof(gf) ) ;
- else if (index < code->n) {
- p = &(code->enc_matrix[index*k] );
- bzero(fec, sz*sizeof(gf));
- for (i = 0; i < k ; i++)
- addmul(fec, src[i], p[i], sz ) ;
- } else
- fprintf(stderr, "Invalid index %d (max %d)\n",
- index, code->n - 1 );
-}
-
-/*
- * shuffle move src packets in their position
- */
-static int
-shuffle(gf *pkt[], int index[], int k)
-{
- int i;
-
- for ( i = 0 ; i < k ; ) {
- if (index[i] >= k || index[i] == i)
- i++ ;
- else {
- /*
- * put pkt in the right position (first check for conflicts).
- */
- int c = index[i] ;
-
- if (index[c] == c) {
- DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
- return 1 ;
- }
- SWAP(index[i], index[c], int) ;
- SWAP(pkt[i], pkt[c], gf *) ;
- }
- }
- DEB( /* just test that it works... */
- for ( i = 0 ; i < k ; i++ ) {
- if (index[i] < k && index[i] != i) {
- fprintf(stderr, "shuffle: after\n");
- for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
- fprintf(stderr, "\n");
- return 1 ;
- }
- }
- )
- return 0 ;
-}
-
-/*
- * build_decode_matrix constructs the encoding matrix given the
- * indexes. The matrix must be already allocated as
- * a vector of k*k elements, in row-major order
- */
-static gf *
-build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[])
-{
- int i , k = code->k ;
- gf *p, *matrix = NEW_GF_MATRIX(k, k);
-
- TICK(ticks[9]);
- for (i = 0, p = matrix ; i < k ; i++, p += k ) {
-#if 1 /* this is simply an optimization, not very useful indeed */
- if (index[i] < k) {
- bzero(p, k*sizeof(gf) );
- p[i] = 1 ;
- } else
-#endif
- if (index[i] < code->n )
- bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) );
- else {
- fprintf(stderr, "decode: invalid index %d (max %d)\n",
- index[i], code->n - 1 );
- free(matrix) ;
- return NULL ;
- }
- }
- TICK(ticks[9]);
- if (invert_mat(matrix, k)) {
- free(matrix);
- matrix = NULL ;
- }
- TOCK(ticks[9]);
- return matrix ;
-}
-
-/*
- * fec_decode receives as input a vector of packets, the indexes of
- * packets, and produces the correct vector as output.
- *
- * Input:
- * code: pointer to code descriptor
- * pkt: pointers to received packets. They are modified
- * to store the output packets (in place)
- * index: pointer to packet indexes (modified)
- * sz: size of each packet
- */
-int
-fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
-{
- gf *m_dec ;
- gf **new_pkt ;
- int row, col , k = code->k ;
-
- if (GF_BITS > 8)
- sz /= 2 ;
-
- if (shuffle(pkt, index, k)) /* error if true */
- return 1 ;
- m_dec = build_decode_matrix(code, pkt, index);
-
- if (m_dec == NULL)
- return 1 ; /* error */
- /*
- * do the actual decoding
- */
- new_pkt = (gf**)my_malloc (k * sizeof (gf * ), "new pkt pointers" );
- for (row = 0 ; row < k ; row++ ) {
- if (index[row] >= k) {
- new_pkt[row] = (gf*) my_malloc (sz * sizeof (gf), "new pkt buffer" );
- bzero(new_pkt[row], sz * sizeof(gf) ) ;
- for (col = 0 ; col < k ; col++ )
- addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
- }
- }
- /*
- * move pkts to their final destination
- */
- for (row = 0 ; row < k ; row++ ) {
- if (index[row] >= k) {
- bcopy(new_pkt[row], pkt[row], sz*sizeof(gf));
- free(new_pkt[row]);
- }
- }
- free(new_pkt);
- free(m_dec);
-
- return 0;
-}
diff --git a/libtransport/src/core/forwarder_interface.h b/libtransport/src/core/forwarder_interface.h
deleted file mode 100644
index a94414d38..000000000
--- a/libtransport/src/core/forwarder_interface.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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 <core/udp_socket_connector.h>
-#include <hicn/transport/core/prefix.h>
-#include <hicn/transport/portability/portability.h>
-#include <hicn/transport/utils/chrono_typedefs.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_.v4.as_u32 = htonl(0x7f00001);
- inet6_address_.v6.as_u8[15] = 0x01;
- }
-
- public:
- 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();
- }
-
- TRANSPORT_ALWAYS_INLINE static bool isControlMessage(const uint8_t *message) {
- return Implementation::isControlMessageImpl(message);
- }
-
- template <typename R>
- TRANSPORT_ALWAYS_INLINE void processControlMessageReply(R &&packet_buffer) {
- return static_cast<Implementation &>(*this).processControlMessageReplyImpl(
- std::forward<R &&>(packet_buffer));
- }
-
- TRANSPORT_ALWAYS_INLINE void closeConnection() {
- return static_cast<Implementation &>(*this).closeConnection();
- }
-
- 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_);
- }
-
-#ifndef __vpp__
- /* In the case of VPP we try to offload checksum computation to hardware */
- packet.setChecksum();
-#endif
- connector_.send(packet.acquireMemBufReference());
- }
-
- TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len) {
- counters_.tx_packets++;
- counters_.tx_bytes += len;
-
- // Perfect forwarding
- connector_.send(packet, len);
- }
-
- 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/core/global_configuration.cc b/libtransport/src/core/global_configuration.cc
index 3e37a30a4..9da37c2fa 100644
--- a/libtransport/src/core/global_configuration.cc
+++ b/libtransport/src/core/global_configuration.cc
@@ -14,8 +14,8 @@
*/
#include <core/global_configuration.h>
+#include <glog/logging.h>
#include <hicn/transport/core/connector.h>
-#include <hicn/transport/utils/log.h>
#include <libconfig.h++>
#include <map>
@@ -32,11 +32,11 @@ bool GlobalConfiguration::parseTransportConfig(const std::string& path) {
try {
cfg.readFile(path.c_str());
} catch (const FileIOException& fioex) {
- TRANSPORT_LOGE("I/O error while reading file: %s", fioex.what());
+ LOG(ERROR) << "I/O error while reading file.";
return false;
} catch (const ParseException& pex) {
- TRANSPORT_LOGE("Parse error at %s:%d - %s", pex.getFile(), pex.getLine(),
- pex.getError());
+ LOG(ERROR) << "Parse error at " << pex.getFile() << ":" << pex.getLine()
+ << " - " << pex.getError();
return false;
}
@@ -50,11 +50,11 @@ bool GlobalConfiguration::parseTransportConfig(const std::string& path) {
for (auto section = root.begin(); section != root.end(); section++) {
std::string name = section->getName();
std::error_code ec;
- TRANSPORT_LOGD("Parsing Section: %s", name.c_str());
+ VLOG(2) << "Parsing Section: " << name;
auto it = configuration_parsers_.find(name);
if (it != configuration_parsers_.end() && !it->second.first) {
- TRANSPORT_LOGD("Found valid configuration parser");
+ VLOG(2) << "Found valid configuration parser";
it->second.second(*section, ec);
it->second.first = true;
}
@@ -64,18 +64,17 @@ bool GlobalConfiguration::parseTransportConfig(const std::string& path) {
}
void GlobalConfiguration::parseConfiguration(const std::string& path) {
- // Check if an environment variable with the configuration path exists. COnf
+ // Check if an environment variable with the configuration path exists. Conf
// variable comes first.
std::unique_lock<std::mutex> lck(cp_mtx_);
-
if (const char* env_c = std::getenv(GlobalConfiguration::conf_file)) {
parseTransportConfig(env_c);
} else if (!path.empty()) {
conf_file_path_ = path;
parseTransportConfig(conf_file_path_);
} else {
- TRANSPORT_LOGD(
- "Called parseConfiguration but no configuration file was provided.");
+ LOG(ERROR)
+ << "Called parseConfiguration but no configuration file was provided.";
}
}
@@ -83,10 +82,9 @@ void GlobalConfiguration::registerConfigurationSetter(
const std::string& key, const SetCallback& set_callback) {
std::unique_lock<std::mutex> lck(cp_mtx_);
if (configuration_setters_.find(key) != configuration_setters_.end()) {
- TRANSPORT_LOGW(
- "Trying to register configuration setter %s twice. Ignoring second "
- "registration attempt.",
- key.c_str());
+ LOG(WARNING) << "Trying to register configuration setter " << key
+ << " twice. Ignoring second "
+ "registration attempt.";
} else {
configuration_setters_.emplace(key, set_callback);
}
@@ -96,10 +94,9 @@ void GlobalConfiguration::registerConfigurationGetter(
const std::string& key, const GetCallback& get_callback) {
std::unique_lock<std::mutex> lck(cp_mtx_);
if (configuration_getters_.find(key) != configuration_getters_.end()) {
- TRANSPORT_LOGW(
- "Trying to register configuration getter %s twice. Ignoring second "
- "registration attempt.",
- key.c_str());
+ LOG(WARNING) << "Trying to register configuration setter " << key
+ << " twice. Ignoring second "
+ "registration attempt.";
} else {
configuration_getters_.emplace(key, get_callback);
}
@@ -109,10 +106,9 @@ void GlobalConfiguration::registerConfigurationParser(
const std::string& key, const ParserCallback& parser) {
std::unique_lock<std::mutex> lck(cp_mtx_);
if (configuration_parsers_.find(key) != configuration_parsers_.end()) {
- TRANSPORT_LOGW(
- "Trying to register configuration key %s twice. Ignoring second "
- "registration attempt.",
- key.c_str());
+ LOG(WARNING) << "Trying to register configuration setter " << key
+ << " twice. Ignoring second "
+ "registration attempt.";
} else {
configuration_parsers_.emplace(key, std::make_pair(false, parser));
diff --git a/libtransport/src/core/hicn_forwarder_interface.cc b/libtransport/src/core/hicn_forwarder_interface.cc
deleted file mode 100644
index 5a0faa360..000000000
--- a/libtransport/src/core/hicn_forwarder_interface.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <core/hicn_forwarder_interface.h>
-
-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;
-} CommandHeader;
-
-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;
-
-typedef struct {
- uint8_t message_type;
- uint8_t command_id;
- uint16_t length;
- uint32_t seq_num;
- char symbolic_or_connid[16];
-} DeleteSelfConnectionCommand;
-
-namespace {
-static constexpr uint8_t addr_inet = 1;
-static constexpr uint8_t addr_inet6 = 2;
-static constexpr uint8_t add_route_command = 3;
-static constexpr uint8_t delete_connection_command = 5;
-static constexpr uint8_t request_light = 0xc0;
-static constexpr char identifier[] = "SELF";
-
-void fillCommandHeader(CommandHeader *header) {
- // Allocate and fill the header
- header->message_type = request_light;
- header->length = 1;
-}
-
-RouteToSelfCommand createCommandRoute(std::unique_ptr<sockaddr> &&addr,
- uint8_t prefix_length) {
- RouteToSelfCommand command = {0};
-
- // check and set IP address
- if (addr->sa_family == AF_INET) {
- command.address_type = addr_inet;
- command.address.ipv4 = ((sockaddr_in *)addr.get())->sin_addr.s_addr;
- } else if (addr->sa_family == AF_INET6) {
- command.address_type = addr_inet6;
- command.address.ipv6 = ((sockaddr_in6 *)addr.get())->sin6_addr;
- }
-
- // Fill remaining payload fields
-#ifndef _WIN32
- strcpy(command.symbolic_or_connid, identifier);
-#else
- strcpy_s(command.symbolic_or_connid, 16, identifier);
-#endif
- command.cost = 1;
- command.len = (uint8_t)prefix_length;
-
- // Allocate and fill the header
- command.command_id = add_route_command;
- fillCommandHeader((CommandHeader *)&command);
-
- return command;
-}
-
-DeleteSelfConnectionCommand createCommandDeleteConnection() {
- DeleteSelfConnectionCommand command = {0};
- fillCommandHeader((CommandHeader *)&command);
- command.command_id = delete_connection_command;
-
-#ifndef _WIN32
- strcpy(command.symbolic_or_connid, identifier);
-#else
- strcpy_s(command.symbolic_or_connid, 16, identifier);
-#endif
-
- return command;
-}
-
-} // namespace
-
-namespace transport {
-
-namespace core {
-
-HicnForwarderInterface::HicnForwarderInterface(UdpSocketConnector &connector)
- : ForwarderInterface<HicnForwarderInterface, UdpSocketConnector>(
- connector) {}
-
-HicnForwarderInterface::~HicnForwarderInterface() {}
-
-void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); }
-
-void HicnForwarderInterface::registerRoute(Prefix &prefix) {
- auto command = createCommandRoute(prefix.toSockaddr(),
- (uint8_t)prefix.getPrefixLength());
- send((uint8_t *)&command, sizeof(RouteToSelfCommand));
-}
-
-void HicnForwarderInterface::closeConnection() {
- auto command = createCommandDeleteConnection();
- send((uint8_t *)&command, sizeof(DeleteSelfConnectionCommand));
- connector_.close();
-}
-
-} // namespace core
-
-} // namespace transport
diff --git a/libtransport/src/core/hicn_forwarder_interface.h b/libtransport/src/core/hicn_forwarder_interface.h
deleted file mode 100644
index c4138c6c2..000000000
--- a/libtransport/src/core/hicn_forwarder_interface.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <core/forwarder_interface.h>
-#include <core/udp_socket_connector.h>
-
-#include <deque>
-
-namespace transport {
-
-namespace core {
-
-class HicnForwarderInterface
- : public ForwarderInterface<HicnForwarderInterface, UdpSocketConnector> {
- static constexpr uint8_t ack_code = 0xc2;
- static constexpr uint8_t nack_code = 0xc3;
-
- 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 = UdpSocketConnector;
-
- HicnForwarderInterface(UdpSocketConnector &connector);
-
- ~HicnForwarderInterface();
-
- void connect(bool is_consumer);
-
- void registerRoute(Prefix &prefix);
-
- std::uint16_t getMtu() { return interface_mtu; }
-
- TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl(
- const uint8_t *message) {
- return message[0] == ack_code || message[0] == nack_code;
- }
-
- TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl(
- Packet::MemBufPtr &&packet_buffer) {
- if (packet_buffer->data()[0] == nack_code) {
- throw errors::RuntimeException(
- "Received Nack message from hicn light forwarder.");
- }
- }
-
- void closeConnection();
-
- private:
- static constexpr std::uint16_t interface_mtu = 1500;
-};
-
-} // namespace core
-
-} // namespace transport
diff --git a/libtransport/src/core/hicn_vapi.c b/libtransport/src/core/hicn_vapi.c
deleted file mode 100644
index be556f3aa..000000000
--- a/libtransport/src/core/hicn_vapi.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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/utils/log.h>
-#include <core/hicn_vapi.h>
-
-#define HICN_VPP_PLUGIN
-#include <hicn/name.h>
-#undef HICN_VPP_PLUGIN
-
-#include <vapi/vapi_safe.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 <vapi/ip.api.vapi.h>
-
-#include <vapi/hicn.api.vapi.h>
-#include <vpp_plugins/hicn/error.h>
-
-/////////////////////////////////////////////////////
-const char *HICN_ERROR_STRING[] = {
-#define _(a, b, c) c,
- foreach_hicn_error
-#undef _
-};
-/////////////////////////////////////////////////////
-
-/*********************** Missing Symbol in vpp libraries
- * *************************/
-u8 *format_vl_api_address_union(u8 *s, va_list *args) { return NULL; }
-
-/*********************************************************************************/
-
-DEFINE_VAPI_MSG_IDS_HICN_API_JSON
-DEFINE_VAPI_MSG_IDS_IP_API_JSON
-
-static vapi_error_e register_prod_app_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_register_prod_app_reply *reply) {
- hicn_producer_output_params *output_params =
- (hicn_producer_output_params *)callback_ctx;
-
- if (reply == NULL) return rv;
-
- output_params->cs_reserved = reply->cs_reserved;
- output_params->prod_addr = (ip_address_t *)malloc(sizeof(ip_address_t));
- memset(output_params->prod_addr, 0, sizeof(ip_address_t));
- if (reply->prod_addr.af == ADDRESS_IP6)
- memcpy(&output_params->prod_addr->v6, reply->prod_addr.un.ip6,
- sizeof(ip6_address_t));
- else
- memcpy(&output_params->prod_addr->v4, reply->prod_addr.un.ip4,
- sizeof(ip4_address_t));
- output_params->face_id = reply->faceid;
-
- return reply->retval;
-}
-
-int hicn_vapi_register_prod_app(vapi_ctx_t ctx,
- hicn_producer_input_params *input_params,
- hicn_producer_output_params *output_params) {
- vapi_lock();
- vapi_msg_hicn_api_register_prod_app *msg =
- vapi_alloc_hicn_api_register_prod_app(ctx);
-
- if (ip46_address_is_ip4((ip46_address_t *)&input_params->prefix->address)) {
- memcpy(&msg->payload.prefix.address.un.ip4, &input_params->prefix->address,
- sizeof(ip4_address_t));
- msg->payload.prefix.address.af = ADDRESS_IP4;
- } else {
- memcpy(&msg->payload.prefix.address.un.ip6, &input_params->prefix->address,
- sizeof(ip6_address_t));
- msg->payload.prefix.address.af = ADDRESS_IP6;
- }
- msg->payload.prefix.len = input_params->prefix->len;
-
- msg->payload.swif = input_params->swif;
- msg->payload.cs_reserved = input_params->cs_reserved;
-
- int ret = vapi_hicn_api_register_prod_app(ctx, msg, register_prod_app_cb,
- output_params);
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e face_prod_del_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_face_prod_del_reply *reply) {
- if (reply == NULL) return rv;
-
- return reply->retval;
-}
-
-int hicn_vapi_face_prod_del(vapi_ctx_t ctx,
- hicn_del_face_app_input_params *input_params) {
- vapi_lock();
- vapi_msg_hicn_api_face_prod_del *msg = vapi_alloc_hicn_api_face_prod_del(ctx);
-
- msg->payload.faceid = input_params->face_id;
-
- int ret = vapi_hicn_api_face_prod_del(ctx, msg, face_prod_del_cb, NULL);
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e register_cons_app_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_register_cons_app_reply *reply) {
- hicn_consumer_output_params *output_params =
- (hicn_consumer_output_params *)callback_ctx;
-
- if (reply == NULL) return rv;
-
- output_params->src6 = (ip_address_t *)malloc(sizeof(ip_address_t));
- output_params->src4 = (ip_address_t *)malloc(sizeof(ip_address_t));
- memset(output_params->src6, 0, sizeof(ip_address_t));
- memset(output_params->src4, 0, sizeof(ip_address_t));
- memcpy(&output_params->src6->v6, &reply->src_addr6.un.ip6,
- sizeof(ip6_address_t));
- memcpy(&output_params->src4->v4, &reply->src_addr4.un.ip4,
- sizeof(ip4_address_t));
-
- output_params->face_id1 = reply->faceid1;
- output_params->face_id2 = reply->faceid2;
-
- return reply->retval;
-}
-
-int hicn_vapi_register_cons_app(vapi_ctx_t ctx,
- hicn_consumer_input_params *input_params,
- hicn_consumer_output_params *output_params) {
- vapi_lock();
- vapi_msg_hicn_api_register_cons_app *msg =
- vapi_alloc_hicn_api_register_cons_app(ctx);
-
- msg->payload.swif = input_params->swif;
-
- int ret = vapi_hicn_api_register_cons_app(ctx, msg, register_cons_app_cb,
- output_params);
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e face_cons_del_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_face_cons_del_reply *reply) {
- if (reply == NULL) return rv;
-
- return reply->retval;
-}
-
-int hicn_vapi_face_cons_del(vapi_ctx_t ctx,
- hicn_del_face_app_input_params *input_params) {
- vapi_lock();
- vapi_msg_hicn_api_face_cons_del *msg = vapi_alloc_hicn_api_face_cons_del(ctx);
-
- msg->payload.faceid = input_params->face_id;
-
- int ret = vapi_hicn_api_face_cons_del(ctx, msg, face_cons_del_cb, NULL);
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e reigster_route_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_ip_route_add_del_reply *reply) {
- if (reply == NULL) return rv;
-
- return reply->retval;
-}
-
-int hicn_vapi_register_route(vapi_ctx_t ctx,
- hicn_producer_set_route_params *input_params) {
- vapi_lock();
- vapi_msg_ip_route_add_del *msg = vapi_alloc_ip_route_add_del(ctx, 1);
-
- msg->payload.is_add = 1;
- if (ip46_address_is_ip4((ip46_address_t *)(input_params->prod_addr))) {
- memcpy(&msg->payload.route.prefix.address.un.ip4, &input_params->prefix->address.v4,
- sizeof(ip4_address_t));
- msg->payload.route.prefix.address.af = ADDRESS_IP4;
- msg->payload.route.prefix.len = input_params->prefix->len;
- } else {
- memcpy(&msg->payload.route.prefix.address.un.ip6, &input_params->prefix->address.v6,
- sizeof(ip6_address_t));
- msg->payload.route.prefix.address.af = ADDRESS_IP6;
- msg->payload.route.prefix.len = input_params->prefix->len;
- }
-
- msg->payload.route.paths[0].sw_if_index = ~0;
- msg->payload.route.paths[0].table_id = 0;
- if (ip46_address_is_ip4((ip46_address_t *)(input_params->prod_addr))) {
- memcpy(&(msg->payload.route.paths[0].nh.address.ip4), input_params->prod_addr->v4.as_u8, sizeof(ip4_address_t));
- msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
- }
- else{
- memcpy(&(msg->payload.route.paths[0].nh.address.ip6), input_params->prod_addr->v6.as_u8, sizeof(ip6_address_t));
- msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
- }
-
- msg->payload.route.paths[0].type = FIB_API_PATH_FLAG_NONE;
- msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
-
- int ret = vapi_ip_route_add_del(ctx, msg, reigster_route_cb, NULL);
-
- vapi_unlock();
- return ret;
-}
-
-char *hicn_vapi_get_error_string(int ret_val) {
- return get_error_string(ret_val);
-}
-
-#endif // __vpp__
diff --git a/libtransport/src/core/hicn_vapi.h b/libtransport/src/core/hicn_vapi.h
deleted file mode 100644
index f5d61e7ef..000000000
--- a/libtransport/src/core/hicn_vapi.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2017-2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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/util/ip_address.h>
-
-#ifdef __vpp__
-
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <vapi/vapi.h>
-
-#include "stdint.h"
-
-typedef struct {
- ip_prefix_t* 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 face_id;
-} hicn_del_face_app_input_params;
-
-typedef struct {
- uint32_t cs_reserved;
- ip_address_t* prod_addr;
- uint32_t face_id;
-} hicn_producer_output_params;
-
-typedef struct {
- ip_address_t* src4;
- ip_address_t* src6;
- uint32_t face_id1;
- uint32_t face_id2;
-} hicn_consumer_output_params;
-
-typedef struct {
- ip_prefix_t* prefix;
- ip_address_t* prod_addr;
-} hicn_producer_set_route_params;
-
-int hicn_vapi_register_prod_app(
- vapi_ctx_t ctx, hicn_producer_input_params* input_params,
- hicn_producer_output_params* output_params);
-
-int hicn_vapi_register_cons_app(
- vapi_ctx_t ctx, hicn_consumer_input_params* input_params,
- hicn_consumer_output_params* output_params);
-
-int hicn_vapi_register_route(
- vapi_ctx_t ctx, hicn_producer_set_route_params* input_params);
-
-int hicn_vapi_face_cons_del(
- vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params);
-
-int hicn_vapi_face_prod_del(
- vapi_ctx_t ctx, hicn_del_face_app_input_params *input_params);
-
-char* hicn_vapi_get_error_string(int ret_val);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __vpp__
diff --git a/libtransport/src/core/interest.cc b/libtransport/src/core/interest.cc
index b4a74762d..9d868ced0 100644
--- a/libtransport/src/core/interest.cc
+++ b/libtransport/src/core/interest.cc
@@ -101,18 +101,6 @@ void Interest::setName(const Name &name) {
}
}
-void Interest::setName(Name &&name) {
- if (hicn_interest_set_name(format_, packet_start_,
- name.getStructReference()) < 0) {
- throw errors::RuntimeException("Error setting interest name.");
- }
-
- if (hicn_interest_get_name(format_, packet_start_,
- name_.getStructReference()) < 0) {
- throw errors::MalformedPacketException();
- }
-}
-
void Interest::setLocator(const ip_address_t &ip_address) {
if (hicn_interest_set_locator(format_, packet_start_, &ip_address) < 0) {
throw errors::RuntimeException("Error setting interest locator.");
@@ -175,8 +163,9 @@ void Interest::encodeSuffixes() {
// We assume interest does not hold signature for the moment.
auto int_manifest_header =
(InterestManifestHeader *)(writableData() + headerSize());
- int_manifest_header->n_suffixes = (uint32_t)suffix_set_.size();
+ int_manifest_header->n_suffixes = suffix_set_.size();
std::size_t additional_length =
+ sizeof(InterestManifestHeader) +
int_manifest_header->n_suffixes * sizeof(uint32_t);
uint32_t *suffix = (uint32_t *)(int_manifest_header + 1);
@@ -184,6 +173,7 @@ void Interest::encodeSuffixes() {
*suffix = *it;
}
+ append(additional_length);
updateLength(additional_length);
}
diff --git a/libtransport/src/core/io_module.cc b/libtransport/src/core/io_module.cc
index 7c2ec2cab..a751eabf5 100644
--- a/libtransport/src/core/io_module.cc
+++ b/libtransport/src/core/io_module.cc
@@ -16,8 +16,8 @@
#ifndef _WIN32
#include <dlfcn.h>
#endif
+#include <glog/logging.h>
#include <hicn/transport/core/io_module.h>
-#include <hicn/transport/utils/log.h>
#ifdef ANDROID
#include <io_modules/udp/hicn_forwarder_module.h>
@@ -45,16 +45,16 @@ IoModule *IoModule::load(const char *module_name) {
handle = dlopen(module_name, RTLD_NOW);
if (!handle) {
if ((error = dlerror()) != 0) {
- TRANSPORT_LOGE("%s", error);
+ LOG(ERROR) << error;
}
return 0;
}
- // link factory method
+ // get factory method
creator = (IoModule * (*)(void)) dlsym(handle, "create_module");
if (!creator) {
if ((error = dlerror()) != 0) {
- TRANSPORT_LOGE("%s", error);
+ LOG(ERROR) << error;
return 0;
}
}
diff --git a/libtransport/src/core/local_connector.cc b/libtransport/src/core/local_connector.cc
index f0e36a3d7..50dadc677 100644
--- a/libtransport/src/core/local_connector.cc
+++ b/libtransport/src/core/local_connector.cc
@@ -14,12 +14,11 @@
*/
#include <core/local_connector.h>
+#include <glog/logging.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/errors/not_implemented_exception.h>
-#include <hicn/transport/utils/log.h>
-
-#include <asio/io_service.hpp>
namespace transport {
namespace core {
@@ -33,7 +32,7 @@ void LocalConnector::send(Packet &packet) {
return;
}
- TRANSPORT_LOGD("Sending packet to local socket.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket.";
io_service_.get().post([this, p{packet.shared_from_this()}]() mutable {
receive_callback_(this, *p, std::make_error_code(std::errc(0)));
});
diff --git a/libtransport/src/core/local_connector.h b/libtransport/src/core/local_connector.h
index b0daa4f53..0e2d8f676 100644
--- a/libtransport/src/core/local_connector.h
+++ b/libtransport/src/core/local_connector.h
@@ -15,17 +15,13 @@
#pragma once
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/core/global_object_pool.h>
#include <hicn/transport/utils/move_wrapper.h>
#include <hicn/transport/utils/shared_ptr_utils.h>
#include <io_modules/forwarder/errors.h>
-#ifndef ASIO_STANDALONE
-#define ASIO_STANDALONE
-#endif
-#include <asio/io_service.hpp>
-
namespace transport {
namespace core {
diff --git a/libtransport/src/core/manifest_format.h b/libtransport/src/core/manifest_format.h
index b759942cb..90d221f5e 100644
--- a/libtransport/src/core/manifest_format.h
+++ b/libtransport/src/core/manifest_format.h
@@ -15,7 +15,7 @@
#pragma once
-#include <hicn/transport/auth/crypto_hasher.h>
+#include <hicn/transport/auth/crypto_hash.h>
#include <hicn/transport/core/name.h>
#include <cinttypes>
diff --git a/libtransport/src/core/manifest_format_fixed.cc b/libtransport/src/core/manifest_format_fixed.cc
index 7076a4c90..11d4a56cb 100644
--- a/libtransport/src/core/manifest_format_fixed.cc
+++ b/libtransport/src/core/manifest_format_fixed.cc
@@ -34,7 +34,7 @@ FixedManifestEncoder::FixedManifestEncoder(Packet &packet,
current_entry_(0),
signature_size_(signature_size) {
if (clear) {
- memset(manifest_header_, 0, sizeof(*manifest_header_));
+ *manifest_header_ = {0};
}
}
@@ -51,7 +51,7 @@ FixedManifestEncoder &FixedManifestEncoder::clearImpl() {
packet_.trimEnd(sizeof(ManifestHeader) +
manifest_header_->number_of_entries * sizeof(ManifestEntry));
current_entry_ = 0;
- memset(manifest_header_, 0, sizeof(*manifest_header_));
+ *manifest_header_ = {0};
return *this;
}
@@ -85,8 +85,8 @@ FixedManifestEncoder &FixedManifestEncoder::setBaseNameImpl(
FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl(
uint32_t suffix, const auth::CryptoHash &hash) {
- auto _hash = hash.getDigest<std::uint8_t>();
- addSuffixHashBytes(suffix, _hash.data(), _hash.length());
+ auto _hash = hash.getDigest();
+ addSuffixHashBytes(suffix, _hash.data(), _hash.size());
return *this;
}
diff --git a/libtransport/src/core/manifest_inline.h b/libtransport/src/core/manifest_inline.h
index fcb1d214f..a487ccfe3 100644
--- a/libtransport/src/core/manifest_inline.h
+++ b/libtransport/src/core/manifest_inline.h
@@ -48,7 +48,7 @@ class ManifestInline
static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest(
const core::Name &manifest_name, ManifestVersion version,
- ManifestType type, auth::CryptoHashType algorithm, bool is_last,
+ ManifestType type, HashType algorithm, bool is_last,
const Name &base_name, NextSegmentCalculationStrategy strategy,
std::size_t signature_size) {
auto manifest = new ManifestInline(manifest_name, signature_size);
@@ -110,24 +110,24 @@ class ManifestInline
// Convert several manifests into a single map from suffixes to packet hashes.
// All manifests must have been decoded beforehand.
- static std::unordered_map<Suffix, HashEntry> getSuffixMap(
+ static std::unordered_map<Suffix, Hash> getSuffixMap(
const std::vector<ManifestInline *> &manifests) {
- std::unordered_map<Suffix, HashEntry> suffix_map;
+ std::unordered_map<Suffix, Hash> suffix_map;
for (auto manifest_ptr : manifests) {
- HashType hash_algorithm = manifest_ptr->getHashAlgorithm();
+ HashType hash_type = manifest_ptr->getHashAlgorithm();
SuffixList suffix_list = manifest_ptr->getSuffixList();
for (auto it = suffix_list.begin(); it != suffix_list.end(); ++it) {
- std::vector<uint8_t> hash(
- it->second, it->second + auth::hash_size_map[hash_algorithm]);
- suffix_map[it->first] = {hash_algorithm, hash};
+ Hash hash(it->second, Hash::getSize(hash_type), hash_type);
+ suffix_map[it->first] = hash;
}
}
return suffix_map;
}
- static std::unordered_map<Suffix, HashEntry> getSuffixMap(
+
+ static std::unordered_map<Suffix, Hash> getSuffixMap(
ManifestInline *manifest) {
return getSuffixMap(std::vector<ManifestInline *>{manifest});
}
diff --git a/libtransport/src/core/memif_connector.cc b/libtransport/src/core/memif_connector.cc
deleted file mode 100644
index 087e8cba8..000000000
--- a/libtransport/src/core/memif_connector.cc
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * 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 <core/memif_connector.h>
-#include <hicn/transport/errors/not_implemented_exception.h>
-
-#ifdef __vpp__
-
-#include <sys/epoll.h>
-
-#include <cstdlib>
-
-extern "C" {
-#include <memif/libmemif.h>
-};
-
-#define CANCEL_TIMER 1
-
-namespace transport {
-
-namespace core {
-
-struct memif_connection {
- 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];
-};
-
-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(std::move(receive_callback), std::move(on_reconnect_callback)),
- memif_worker_(nullptr),
- timer_set_(false),
- send_timer_(std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
- disconnect_timer_(
- std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
- io_service_(io_service),
- packet_counter_(0),
- memif_connection_(std::make_unique<memif_connection_t>()),
- tx_buf_counter_(0),
- is_reconnection_(false),
- data_available_(false),
- app_name_(app_name),
- 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_LOGE("memif_init: %s", memif_strerror(err));
- }
-}
-
-void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
- state_ = ConnectorState::CONNECTING;
-
- memif_id_ = memif_id;
- socket_filename_ = "/run/vpp/memif.sock";
-
- createMemif(memif_id, memif_mode, nullptr);
-
- work_ = std::make_unique<asio::io_service::work>(io_service_);
-
- while (state_ != ConnectorState::CONNECTED) {
- 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_LOGE("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_.get();
-
- /* 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) + 1);
- args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
-
- int err;
-
- err = memif_create_socket(&args.socket, socket_filename_.c_str(), nullptr);
-
- if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- throw errors::RuntimeException(memif_strerror(err));
- }
-
- 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 */
-
- /* 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_.get();
-
- 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_LOGE("memif_delete: %s", memif_strerror(err));
- }
-
- if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) {
- TRANSPORT_LOGE("memif delete fail");
- }
-
- return 0;
-}
-
-int MemifConnector::controlFdUpdate(int fd, uint8_t events, void *private_ctx) {
- /* 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_LOGE("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_.get();
- 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_LOGE("memif_buffer_alloc: %s", memif_strerror(err));
- return -1;
- }
-
- c->tx_buf_num += r;
- return r;
-}
-
-int MemifConnector::txBurst(uint16_t qid) {
- memif_connection_t *c = memif_connection_.get();
- 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_LOGE("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_LOGE("memif_tx_burst: %s", memif_strerror(err));
- c->tx_buf_num -= r;
- return -1;
- }
-
- c->tx_buf_num -= r;
- return 0;
-}
-
-void MemifConnector::sendCallback(const std::error_code &ec) {
- timer_set_ = false;
-
- if (TRANSPORT_EXPECT_TRUE(!ec && state_ == ConnectorState::CONNECTED)) {
- doSend();
- }
-}
-
-void MemifConnector::processInputBuffer(std::uint16_t total_packets) {
- Packet::MemBufPtr ptr;
-
- for (; total_packets > 0; total_packets--) {
- if (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) {
- MemifConnector *connector = (MemifConnector *)private_ctx;
- connector->state_ = ConnectorState::CONNECTED;
- memif_refill_queue(conn, 0, -1, 0);
-
- 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) {
- MemifConnector *connector = (MemifConnector *)private_ctx;
- connector->state_ = ConnectorState::CLOSED;
- return 0;
-}
-
-void MemifConnector::threadMain() { event_reactor_.runEventLoop(1000); }
-
-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_.get();
- int err = MEMIF_ERR_SUCCESS, ret_val;
- uint16_t total_packets = 0;
- 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_LOGE("memif_rx_burst: %s", memif_strerror(err));
- goto error;
- }
-
- c->rx_buf_num += rx;
-
- if (TRANSPORT_EXPECT_FALSE(connector->io_service_.stopped())) {
- TRANSPORT_LOGE("socket stopped: ignoring %u packets", rx);
- goto error;
- }
-
- std::size_t packet_length;
- for (int i = 0; i < rx; i++) {
- auto packet = connector->getPacket();
- packet_length = (c->rx_bufs + i)->len;
- std::memcpy(packet->writableData(),
- reinterpret_cast<const uint8_t *>((c->rx_bufs + i)->data),
- packet_length);
- packet->append(packet_length);
-
- if (!connector->input_buffer_.push(std::move(packet))) {
- TRANSPORT_LOGE("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)
- }
- }
-
- /* 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_LOGE("memif_buffer_free: %s", memif_strerror(err));
- }
-
- c->rx_buf_num -= rx;
- total_packets += rx;
-
- } while (ret_val == MEMIF_ERR_NOBUF);
-
- connector->io_service_.post(
- std::bind(&MemifConnector::processInputBuffer, connector, total_packets));
-
- return 0;
-
-error:
- err = memif_refill_queue(c->conn, qid, rx, 0);
-
- if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err));
- }
- c->rx_buf_num -= rx;
-
- return 0;
-}
-
-void MemifConnector::close() {
- if (state_ != ConnectorState::CLOSED) {
- disconnect_timer_->expiresFromNow(std::chrono::microseconds(50));
- disconnect_timer_->asyncWait([this](const std::error_code &ec) {
- deleteMemif();
- event_reactor_.stop();
- work_.reset();
- });
-
- if (memif_worker_ && memif_worker_->joinable()) {
- memif_worker_->join();
- }
- }
-}
-
-void MemifConnector::send(const Packet::MemBufPtr &packet) {
- {
- utils::SpinLock::Acquire locked(write_msgs_lock_);
- output_buffer_.push_back(packet);
- }
-#if 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
-}
-
-int MemifConnector::doSend() {
- std::size_t max = 0;
- int32_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;
- n = bufferAlloc(max, memif_connection_->tx_qid);
-
- if (TRANSPORT_EXPECT_FALSE(n < 0)) {
- TRANSPORT_LOGE("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);
-
- 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::send(const uint8_t *packet, std::size_t len,
- const PacketSentCallback &packet_sent) {
- throw errors::NotImplementedException();
-}
-
-} // end namespace core
-
-} // end namespace transport
-
-#endif // __vpp__
diff --git a/libtransport/src/core/memif_connector.h b/libtransport/src/core/memif_connector.h
deleted file mode 100644
index 8a0e9efad..000000000
--- a/libtransport/src/core/memif_connector.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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 <core/connector.h>
-#include <hicn/transport/config.h>
-#include <hicn/transport/portability/portability.h>
-#include <hicn/transport/utils/ring_buffer.h>
-//#include <hicn/transport/core/hicn_vapi.h>
-#include <utils/epoll_event_reactor.h>
-#include <utils/fd_deadline_timer.h>
-
-#include <asio.hpp>
-#include <deque>
-#include <mutex>
-#include <thread>
-
-#ifdef __vpp__
-
-#define _Static_assert static_assert
-
-namespace transport {
-
-namespace core {
-
-typedef struct memif_connection memif_connection_t;
-
-#define APP_NAME "libtransport"
-#define IF_NAME "vpp_connection"
-
-#define MEMIF_BUF_SIZE 2048
-#define MEMIF_LOG2_RING_SIZE 13
-#define MAX_MEMIF_BUFS (1 << MEMIF_LOG2_RING_SIZE)
-
-class MemifConnector : public Connector {
- typedef void *memif_conn_handle_t;
-
- 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);
-
- 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, void *private_ctx);
-
- 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(std::uint16_t total_packets);
-
- 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_;
- std::atomic_bool timer_set_;
- std::unique_ptr<utils::FdDeadlineTimer> send_timer_;
- std::unique_ptr<utils::FdDeadlineTimer> disconnect_timer_;
- asio::io_service &io_service_;
- std::unique_ptr<asio::io_service::work> work_;
- uint32_t packet_counter_;
- std::unique_ptr<memif_connection_t> memif_connection_;
- uint16_t tx_buf_counter_;
-
- PacketRing input_buffer_;
- bool is_reconnection_;
- bool data_available_;
- uint32_t memif_id_;
- uint8_t memif_mode_;
- std::string app_name_;
- uint16_t transmission_index_;
- 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/core/memif_vapi.c b/libtransport/src/core/memif_vapi.c
deleted file mode 100644
index ea3513306..000000000
--- a/libtransport/src/core/memif_vapi.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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 <core/memif_vapi.h>
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <semaphore.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <vapi/vapi_safe.h>
-#include <vppinfra/clib.h>
-
-DEFINE_VAPI_MSG_IDS_MEMIF_API_JSON
-
-static vapi_error_e memif_details_cb(vapi_ctx_t ctx, void *callback_ctx,
- vapi_error_e rv, bool is_last,
- vapi_payload_memif_details *reply) {
- uint32_t *last_memif_id = (uint32_t *)callback_ctx;
- uint32_t current_memif_id = 0;
- if (reply != NULL) {
- current_memif_id = reply->id;
- } else {
- return rv;
- }
-
- if (current_memif_id >= *last_memif_id) {
- *last_memif_id = current_memif_id + 1;
- }
-
- return rv;
-}
-
-int memif_vapi_get_next_memif_id(vapi_ctx_t ctx, uint32_t *memif_id) {
- vapi_lock();
- vapi_msg_memif_dump *msg = vapi_alloc_memif_dump(ctx);
- int ret = vapi_memif_dump(ctx, msg, memif_details_cb, memif_id);
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e memif_create_cb(vapi_ctx_t ctx, void *callback_ctx,
- vapi_error_e rv, bool is_last,
- vapi_payload_memif_create_reply *reply) {
- memif_output_params_t *output_params = (memif_output_params_t *)callback_ctx;
-
- if (reply == NULL) return rv;
-
- output_params->sw_if_index = reply->sw_if_index;
-
- return rv;
-}
-
-int memif_vapi_create_memif(vapi_ctx_t ctx, memif_create_params_t *input_params,
- memif_output_params_t *output_params) {
- vapi_lock();
- vapi_msg_memif_create *msg = vapi_alloc_memif_create(ctx);
-
- int ret = 0;
- if (input_params->socket_id == ~0) {
- // invalid socket-id
- ret = -1;
- goto END;
- }
-
- if (!is_pow2(input_params->ring_size)) {
- // ring size must be power of 2
- ret = -1;
- goto END;
- }
-
- if (input_params->rx_queues > 255 || input_params->rx_queues < 1) {
- // rx queue must be between 1 - 255
- ret = -1;
- goto END;
- }
-
- if (input_params->tx_queues > 255 || input_params->tx_queues < 1) {
- // tx queue must be between 1 - 255
- ret = -1;
- goto END;
- }
-
- msg->payload.role = input_params->role;
- msg->payload.mode = input_params->mode;
- msg->payload.rx_queues = input_params->rx_queues;
- msg->payload.tx_queues = input_params->tx_queues;
- msg->payload.id = input_params->id;
- msg->payload.socket_id = input_params->socket_id;
- msg->payload.ring_size = input_params->ring_size;
- msg->payload.buffer_size = input_params->buffer_size;
-
- ret = vapi_memif_create(ctx, msg, memif_create_cb, output_params);
-END:
- vapi_unlock();
- return ret;
-}
-
-static vapi_error_e memif_delete_cb(vapi_ctx_t ctx, void *callback_ctx,
- vapi_error_e rv, bool is_last,
- vapi_payload_memif_delete_reply *reply) {
- if (reply == NULL) return rv;
-
- return reply->retval;
-}
-
-int memif_vapi_delete_memif(vapi_ctx_t ctx, uint32_t sw_if_index) {
- vapi_lock();
- vapi_msg_memif_delete *msg = vapi_alloc_memif_delete(ctx);
-
- msg->payload.sw_if_index = sw_if_index;
-
- int ret = vapi_memif_delete(ctx, msg, memif_delete_cb, NULL);
- vapi_unlock();
- return ret;
-}
-
-#endif // __vpp__
diff --git a/libtransport/src/core/memif_vapi.h b/libtransport/src/core/memif_vapi.h
deleted file mode 100644
index c045cf093..000000000
--- a/libtransport/src/core/memif_vapi.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 <vapi/memif.api.vapi.h>
-#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;
-
-int memif_vapi_get_next_memif_id(vapi_ctx_t ctx,
- uint32_t *memif_id);
-
-int memif_vapi_create_memif(vapi_ctx_t ctx,
- memif_create_params_t *input_params,
- memif_output_params_t *output_params);
-
-int memif_vapi_delete_memif(vapi_ctx_t ctx,
- uint32_t sw_if_index);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __vpp__ \ No newline at end of file
diff --git a/libtransport/src/core/packet.cc b/libtransport/src/core/packet.cc
index 6f237729a..51337201f 100644
--- a/libtransport/src/core/packet.cc
+++ b/libtransport/src/core/packet.cc
@@ -13,10 +13,11 @@
* limitations under the License.
*/
+#include <glog/logging.h>
+#include <hicn/transport/auth/crypto_hash.h>
#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" {
#ifndef _WIN32
@@ -250,7 +251,7 @@ Packet::Format Packet::getFormat() const {
*/
if (format_ == HF_UNSPEC && length()) {
if (hicn_packet_get_format(packet_start_, &format_) < 0) {
- TRANSPORT_LOGE("Unexpected packet format.");
+ LOG(ERROR) << "Unexpected packet format HF_UNSPEC.";
}
}
@@ -262,12 +263,12 @@ std::shared_ptr<utils::MemBuf> Packet::acquireMemBufReference() {
}
void Packet::dump() const {
- TRANSPORT_LOGI("HEADER -- Length: %zu", headerSize());
- TRANSPORT_LOGI("PAYLOAD -- Length: %zu", payloadSize());
+ LOG(INFO) << "HEADER -- Length: " << headerSize();
+ LOG(INFO) << "PAYLOAD -- Length: " << payloadSize();
const utils::MemBuf *current = this;
do {
- TRANSPORT_LOGI("MemBuf Length: %zu", current->length());
+ LOG(INFO) << "MemBuf Length: " << current->length();
dump((uint8_t *)current->data(), current->length());
current = current->next();
} while (current != this);
@@ -289,6 +290,19 @@ void Packet::setSignatureSize(std::size_t size_bytes) {
}
}
+void Packet::setSignatureSizeGap(std::size_t size_bytes) {
+ if (!authenticationHeader()) {
+ throw errors::RuntimeException("Packet without Authentication Header.");
+ }
+
+ int ret = hicn_packet_set_signature_gap(format_, packet_start_,
+ (uint8_t)size_bytes);
+
+ if (ret < 0) {
+ throw errors::RuntimeException("Error setting signature size.");
+ }
+}
+
uint8_t *Packet::getSignature() const {
if (!authenticationHeader()) {
throw errors::RuntimeException("Packet without Authentication Header.");
@@ -392,8 +406,8 @@ auth::KeyId Packet::getKeyId() const {
}
auth::CryptoHash Packet::computeDigest(auth::CryptoHashType algorithm) const {
- auth::CryptoHasher hasher(static_cast<auth::CryptoHashType>(algorithm));
- hasher.init();
+ auth::CryptoHash hash;
+ hash.setType(algorithm);
// Copy IP+TCP/ICMP header before zeroing them
hicn_header_t header_copy;
@@ -402,15 +416,10 @@ auth::CryptoHash Packet::computeDigest(auth::CryptoHashType algorithm) const {
const_cast<Packet *>(this)->resetForHash();
- const utils::MemBuf *current = this;
- do {
- hasher.updateBytes(current->data(), current->length());
- current = current->next();
- } while (current != this);
-
+ hash.computeDigest(this);
hicn_packet_copy_header(format_, &header_copy, packet_start_, false);
- return hasher.finalize();
+ return hash;
}
bool Packet::checkIntegrity() const {
diff --git a/libtransport/src/core/pending_interest.h b/libtransport/src/core/pending_interest.h
index ca6411ddf..99a8bd327 100644
--- a/libtransport/src/core/pending_interest.h
+++ b/libtransport/src/core/pending_interest.h
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/core/name.h>
@@ -23,8 +24,6 @@
#include <hicn/transport/portability/portability.h>
#include <utils/deadline_timer.h>
-#include <asio/steady_timer.hpp>
-
namespace transport {
namespace core {
@@ -80,8 +79,8 @@ class PendingInterest {
return std::move(interest_);
}
- TRANSPORT_ALWAYS_INLINE void setInterest(Interest::Ptr &&interest) {
- interest_ = std::move(interest);
+ TRANSPORT_ALWAYS_INLINE void setInterest(Interest::Ptr &interest) {
+ interest_ = interest;
}
TRANSPORT_ALWAYS_INLINE const OnContentObjectCallback &getOnDataCallback()
diff --git a/libtransport/src/core/portal.cc b/libtransport/src/core/portal.cc
index 33335e542..c4c0cf8ba 100644
--- a/libtransport/src/core/portal.cc
+++ b/libtransport/src/core/portal.cc
@@ -72,7 +72,7 @@ std::string getIoModulePath(const std::string& name,
#elif defined(MACINTOSH)
std::string extension = ".dylib";
#elif defined(WINDOWS)
- std::string extension = ".lib";
+ std::string extension = ".lib";
#else
#error "Platform not supported.";
#endif
@@ -88,8 +88,7 @@ std::string getIoModulePath(const std::string& name,
for (auto& p : paths) {
if (p.at(0) != '/') {
- TRANSPORT_LOGW("Path %s is not an absolute path. Ignoring it.",
- p.c_str());
+ LOG(WARNING) << "Path " << p << " is not an absolute path. Ignoring it.";
continue;
}
diff --git a/libtransport/src/core/portal.h b/libtransport/src/core/portal.h
index 59254cf7b..f6a9ce85b 100644
--- a/libtransport/src/core/portal.h
+++ b/libtransport/src/core/portal.h
@@ -16,7 +16,9 @@
#pragma once
#include <core/pending_interest.h>
+#include <glog/logging.h>
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/core/io_module.h>
@@ -27,10 +29,7 @@
#include <hicn/transport/interfaces/portal.h>
#include <hicn/transport/portability/portability.h>
#include <hicn/transport/utils/fixed_block_allocator.h>
-#include <hicn/transport/utils/log.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <future>
#include <memory>
#include <queue>
@@ -136,7 +135,7 @@ class CustomAllocatorHandler {
}
template <typename... Args>
- void operator()(Args &&...args) {
+ void operator()(Args &&... args) {
handler_(std::forward<Args>(args)...);
}
@@ -277,7 +276,8 @@ class Portal {
if (!io_module_) {
pending_interest_hash_table_.reserve(portal_details::pit_size);
io_module_.reset(IoModule::load(io_module_path_.c_str()));
- assert(io_module_);
+
+ CHECK(io_module_);
io_module_->init(std::bind(&Portal::processIncomingMessages, this,
std::placeholders::_1, std::placeholders::_2,
@@ -298,7 +298,7 @@ class Portal {
* Compute name hash
*/
TRANSPORT_ALWAYS_INLINE uint32_t getHash(const Name &name) {
- return name.getHash32() + name.getSuffix();
+ return name.getHash32(false) + name.getSuffix();
}
/**
@@ -338,15 +338,16 @@ class Portal {
interest->encodeSuffixes();
io_module_->send(*interest);
- uint32_t initial_hash = interest->getName().getHash32();
+ uint32_t initial_hash = interest->getName().getHash32(false);
auto hash = initial_hash + interest->getName().getSuffix();
+ uint32_t seq = interest->getName().getSuffix();
uint32_t *suffix = interest->firstSuffix();
auto n_suffixes = interest->numberOfSuffixes();
uint32_t counter = 0;
// Set timers
do {
auto pending_interest = packet_pool_.getPendingInterest();
- pending_interest->setInterest(std::move(interest));
+ pending_interest->setInterest(interest);
pending_interest->setOnContentObjectCallback(
std::move(on_content_object_callback));
pending_interest->setOnTimeoutCallback(
@@ -354,8 +355,9 @@ class Portal {
pending_interest->startCountdown(
portal_details::makeCustomAllocatorHandler(
- async_callback_memory_, std::bind(&Portal::timerHandler, this,
- std::placeholders::_1, hash)));
+ async_callback_memory_,
+ std::bind(&Portal::timerHandler, this, std::placeholders::_1,
+ hash, seq)));
auto it = pending_interest_hash_table_.find(hash);
if (it != pending_interest_hash_table_.end()) {
@@ -370,6 +372,7 @@ class Portal {
if (suffix) {
hash = initial_hash + *suffix;
+ seq = *suffix;
suffix++;
}
@@ -385,7 +388,7 @@ class Portal {
* @param hash - The index of the interest in the pending interest hash table.
*/
TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec,
- uint32_t hash) {
+ uint32_t hash, uint32_t seq) {
bool is_stopped = io_service_.stopped();
if (TRANSPORT_EXPECT_FALSE(is_stopped)) {
return;
@@ -398,11 +401,13 @@ class Portal {
PendingInterest::Ptr ptr = std::move(it->second);
pending_interest_hash_table_.erase(it);
auto _int = ptr->getInterest();
+ Name &name = const_cast<Name &>(_int->getName());
+ name.setSuffix(seq);
if (ptr->getOnTimeoutCallback() != UNSET_CALLBACK) {
- ptr->on_interest_timeout_callback_(std::move(_int));
+ ptr->on_interest_timeout_callback_(_int, name);
} else if (consumer_callback_) {
- consumer_callback_->onTimeout(std::move(_int));
+ consumer_callback_->onTimeout(_int, name);
}
}
}
@@ -516,6 +521,15 @@ class Portal {
}
}
+ /**
+ * Check if the transport is connected to a forwarder or not
+ */
+ TRANSPORT_ALWAYS_INLINE bool isConnectedToFwd() {
+ std::string mod = io_module_path_.substr(0, io_module_path_.find("."));
+ if (mod == "forwarder_module") return false;
+ return true;
+ }
+
private:
/**
* Clear the pending interest hash table.
@@ -578,7 +592,7 @@ class Portal {
processInterest(static_cast<Interest &>(packet_buffer));
}
} else {
- TRANSPORT_LOGE("Received not supported packet. Ignoring it.");
+ LOG(ERROR) << "Received not supported packet. Ignoring it.";
}
}
@@ -597,6 +611,7 @@ class Portal {
TRANSPORT_ALWAYS_INLINE void processInterest(Interest &interest) {
// Interest for a producer
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "processInterest " << interest.getName();
if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) {
producer_callback_->onInterest(interest);
}
@@ -612,13 +627,13 @@ class Portal {
*/
TRANSPORT_ALWAYS_INLINE void processContentObject(
ContentObject &content_object) {
- TRANSPORT_LOGD("processContentObject %s",
- content_object.getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "processContentObject " << content_object.getName();
uint32_t hash = getHash(content_object.getName());
auto it = pending_interest_hash_table_.find(hash);
if (it != pending_interest_hash_table_.end()) {
- TRANSPORT_LOGD("Found pending interest.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest.";
PendingInterest::Ptr interest_ptr = std::move(it->second);
pending_interest_hash_table_.erase(it);
@@ -631,7 +646,8 @@ class Portal {
consumer_callback_->onContentObject(*_int, content_object);
}
} else {
- TRANSPORT_LOGD("No interest pending for received content object.");
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "No interest pending for received content object.";
}
}
diff --git a/libtransport/src/core/raw_socket_connector.cc b/libtransport/src/core/raw_socket_connector.cc
deleted file mode 100644
index 4d780959b..000000000
--- a/libtransport/src/core/raw_socket_connector.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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/conversions.h>
-#include <hicn/transport/utils/log.h>
-
-#include <core/raw_socket_connector.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(std::move(receive_callback), std::move(on_reconnect_callback)),
- 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),
- 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) {
- state_ = ConnectorState::CONNECTING;
- 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::send(const uint8_t *packet, std::size_t len,
- const PacketSentCallback &packet_sent) {
- if (packet_sent != 0) {
- socket_.async_send(
- asio::buffer(packet, len),
- [packet_sent](std::error_code ec, std::size_t /*length*/) {
- packet_sent();
- });
- } else {
- if (state_ == ConnectorState::CONNECTED) {
- socket_.send(asio::buffer(packet, len));
- }
- }
-}
-
-void RawSocketConnector::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_TRUE(state_ == ConnectorState::CONNECTED)) {
- 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_ = 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() {
- state_ = ConnectorState::CONNECTED;
- socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_)));
-}
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/core/raw_socket_connector.h b/libtransport/src/core/raw_socket_connector.h
deleted file mode 100644
index 1d4e9cb39..000000000
--- a/libtransport/src/core/raw_socket_connector.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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/name.h>
-
-#include <core/connector.h>
-
-#include <linux/if_packet.h>
-#include <net/ethernet.h>
-#include <sys/socket.h>
-#include <asio.hpp>
-#include <asio/steady_timer.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 connect(const std::string &interface_name,
- const std::string &mac_address_str);
-
- 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_;
- std::string app_name_;
-};
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/core/raw_socket_interface.cc b/libtransport/src/core/raw_socket_interface.cc
deleted file mode 100644
index 7ee2a844d..000000000
--- a/libtransport/src/core/raw_socket_interface.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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/linux.h>
-
-#include <core/raw_socket_interface.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 = {0};
- utils::retrieveInterfaceAddress(output_interface_, &address);
-
- std::memcpy(&inet6_address_.v6.as_u8, &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/core/raw_socket_interface.h b/libtransport/src/core/raw_socket_interface.h
deleted file mode 100644
index c06d14637..000000000
--- a/libtransport/src/core/raw_socket_interface.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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 <core/forwarder_interface.h>
-#include <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; }
-
- TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl(
- const uint8_t *message) {
- return false;
- }
-
- TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl(
- Packet::MemBufPtr &&packet_buffer) {}
-
- TRANSPORT_ALWAYS_INLINE void closeConnection(){};
-
- private:
- static constexpr std::uint16_t interface_mtu = 1500;
- std::string remote_mac_address_;
-};
-
-} // namespace core
-
-} // namespace transport
diff --git a/libtransport/src/core/rs.cc b/libtransport/src/core/rs.cc
deleted file mode 100644
index 33270736d..000000000
--- a/libtransport/src/core/rs.cc
+++ /dev/null
@@ -1,370 +0,0 @@
-
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <core/fec.h>
-#include <core/rs.h>
-#include <hicn/transport/core/global_object_pool.h>
-#include <hicn/transport/utils/log.h>
-
-#include <cassert>
-
-namespace transport {
-namespace core {
-namespace fec {
-
-BlockCode::BlockCode(uint32_t k, uint32_t n, struct fec_parms *code)
- : Packets(),
- k_(k),
- n_(n),
- code_(code),
- max_buffer_size_(0),
- current_block_size_(0),
- to_decode_(false) {
- sorted_index_.reserve(n);
-}
-
-bool BlockCode::addRepairSymbol(const fec::buffer &packet, uint32_t i) {
- // Get index
- to_decode_ = true;
- TRANSPORT_LOGD("adding symbol of size %zu", packet->length());
- return addSymbol(packet, i, packet->length() - sizeof(fec_header));
-}
-
-bool BlockCode::addSourceSymbol(const fec::buffer &packet, uint32_t i) {
- return addSymbol(packet, i, packet->length());
-}
-
-bool BlockCode::addSymbol(const fec::buffer &packet, uint32_t i,
- std::size_t size) {
- if (size > max_buffer_size_) {
- max_buffer_size_ = size;
- }
-
- operator[](current_block_size_++) = std::make_pair(i, packet);
-
- if (current_block_size_ >= k_) {
- if (to_decode_) {
- decode();
- } else {
- encode();
- }
-
- clear();
- return false;
- }
-
- return true;
-}
-
-void BlockCode::encode() {
- gf **data = new gf*[k_];
- uint32_t *old_values = new uint32_t[k_];
- uint32_t base = operator[](0).first;
-
- // Set packet length in first 2 bytes
- for (uint32_t i = 0; i < k_; i++) {
- auto &packet = operator[](i).second;
-
- TRANSPORT_LOGD("Current buffer size: %zu", packet->length());
-
- auto ret = packet->ensureCapacityAndFillUnused(max_buffer_size_, 0);
- if (TRANSPORT_EXPECT_FALSE(ret == false)) {
- throw errors::RuntimeException(
- "Provided packet is not suitable to be used as FEC source packet. "
- "Aborting.");
- }
-
- // Buffers should hold 2 bytes before the starting pointer, in order to be
- // able to set the length for the encoding operation
- packet->prepend(2);
- uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData());
-
- old_values[i] = *length;
- *length = htons(u_short(packet->length() - LEN_SIZE_BYTES));
-
- data[i] = packet->writableData();
-
- }
-
- // Finish to fill source block with the buffers to hold the repair symbols
- for (uint32_t i = k_; i < n_; i++) {
- // For the moment we get a packet from the pool here.. later we'll need to
- // require a packet from the caller with a callback.
- auto packet = PacketManager<>::getInstance().getMemBuf();
- packet->append(max_buffer_size_ + sizeof(fec_header) + LEN_SIZE_BYTES);
- fec_header *fh = reinterpret_cast<fec_header *>(packet->writableData());
-
- fh->setSeqNumberBase(base);
- fh->setNFecSymbols(n_ - k_);
- fh->setEncodedSymbolId(i);
- fh->setSourceBlockLen(n_);
-
- packet->trimStart(sizeof(fec_header));
-
- data[i] = packet->writableData();
- operator[](i) = std::make_pair(i, std::move(packet));
- }
-
- // Generate repair symbols and put them in corresponding buffers
- TRANSPORT_LOGD("Calling encode with max_buffer_size_ = %zu",
- max_buffer_size_);
- for (uint32_t i = k_; i < n_; i++) {
- fec_encode(code_, data, data[i], i, (int)(max_buffer_size_ + LEN_SIZE_BYTES));
- }
-
- // Restore original content of buffer space used to store the length
- for (uint32_t i = 0; i < k_; i++) {
- auto &packet = operator[](i).second;
- uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData());
- *length = old_values[i];
- packet->trimStart(2);
- }
-
- // Re-include header in repair packets
- for (uint32_t i = k_; i < n_; i++) {
- auto &packet = operator[](i).second;
- TRANSPORT_LOGD("Produced repair symbol of size = %zu", packet->length());
- packet->prepend(sizeof(fec_header));
- }
- delete [] data;
- delete [] old_values;
-}
-
-void BlockCode::decode() {
- gf **data = new gf*[k_];
- uint32_t *index = new uint32_t[k_];
-
- for (uint32_t i = 0; i < k_; i++) {
- auto &packet = operator[](i).second;
- index[i] = operator[](i).first;
- sorted_index_[i] = index[i];
-
- if (index[i] < k_) {
- TRANSPORT_LOGD("DECODE SOURCE - index %u - Current buffer size: %zu",
- index[i], packet->length());
- // This is a source packet. We need to prepend the length and fill
- // additional space to 0
-
- // Buffers should hold 2 bytes before the starting pointer, in order to be
- // able to set the length for the encoding operation
- packet->prepend(LEN_SIZE_BYTES);
- packet->ensureCapacityAndFillUnused(max_buffer_size_, 0);
- uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData());
-
- *length = htons(u_short(packet->length() - LEN_SIZE_BYTES));
- } else {
- TRANSPORT_LOGD("DECODE SYMBOL - index %u - Current buffer size: %zu",
- index[i], packet->length());
- packet->trimStart(sizeof(fec_header));
- }
-
- data[i] = packet->writableData();
- delete [] data;
- delete [] index;
- }
-
- // We decode the source block
- TRANSPORT_LOGD("Calling decode with max_buffer_size_ = %zu",
- max_buffer_size_);
- fec_decode(code_, data, reinterpret_cast<int *>(index), (int)max_buffer_size_);
-
- // Find the index in the block for recovered packets
- for (uint32_t i = 0; i < k_; i++) {
- if (index[i] != i) {
- for (uint32_t j = 0; j < k_; j++)
- if (sorted_index_[j] == uint32_t(index[i])) {
- sorted_index_[j] = i;
- }
- }
- }
-
- // Reorder block by index with in-place sorting
- for (uint32_t i = 0; i < k_; i++) {
- for (uint32_t j = sorted_index_[i]; j != i; j = sorted_index_[i]) {
- std::swap(sorted_index_[j], sorted_index_[i]);
- std::swap(operator[](j), operator[](i));
- }
- }
-
- // Adjust length according to the one written in the source packet
- for (uint32_t i = 0; i < k_; i++) {
- auto &packet = operator[](i).second;
- uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData());
- packet->trimStart(2);
- packet->setLength(ntohs(*length));
- }
-}
-
-void BlockCode::clear() {
- current_block_size_ = 0;
- max_buffer_size_ = 0;
- sorted_index_.clear();
- to_decode_ = false;
-}
-
-void rs::MatrixDeleter::operator()(struct fec_parms *params) {
- fec_free(params);
-}
-
-rs::Codes rs::createCodes() {
- Codes ret;
-
- ret.emplace(std::make_pair(1, 3), Matrix(fec_new(1, 3), MatrixDeleter()));
- ret.emplace(std::make_pair(6, 10), Matrix(fec_new(6, 10), MatrixDeleter()));
- ret.emplace(std::make_pair(8, 32), Matrix(fec_new(8, 32), MatrixDeleter()));
- ret.emplace(std::make_pair(10, 30), Matrix(fec_new(10, 30), MatrixDeleter()));
- ret.emplace(std::make_pair(16, 24), Matrix(fec_new(16, 24), MatrixDeleter()));
- ret.emplace(std::make_pair(10, 40), Matrix(fec_new(10, 40), MatrixDeleter()));
- ret.emplace(std::make_pair(10, 60), Matrix(fec_new(10, 60), MatrixDeleter()));
- ret.emplace(std::make_pair(10, 90), Matrix(fec_new(10, 90), MatrixDeleter()));
-
- return ret;
-}
-
-rs::Codes rs::codes_ = createCodes();
-
-rs::rs(uint32_t k, uint32_t n) : k_(k), n_(n) {}
-
-void rs::setFECCallback(const PacketsReady &callback) {
- fec_callback_ = callback;
-}
-
-encoder::encoder(uint32_t k, uint32_t n)
- : rs(k, n),
- current_code_(codes_[std::make_pair(k, n)].get()),
- source_block_(k_, n_, current_code_) {}
-
-void encoder::consume(const fec::buffer &packet, uint32_t index) {
- if (!source_block_.addSourceSymbol(packet, index)) {
- std::vector<buffer> repair_packets;
- for (uint32_t i = k_; i < n_; i++) {
- repair_packets.emplace_back(std::move(source_block_[i].second));
- }
- fec_callback_(repair_packets);
- }
-}
-
-decoder::decoder(uint32_t k, uint32_t n) : rs(k, n) {}
-
-void decoder::recoverPackets(SourceBlocks::iterator &src_block_it) {
- TRANSPORT_LOGD("recoverPackets for %u", k_);
- auto &src_block = src_block_it->second;
- std::vector<buffer> source_packets(k_);
- for (uint32_t i = 0; i < src_block.getK(); i++) {
- source_packets[i] = std::move(src_block[i].second);
- }
-
- fec_callback_(source_packets);
- processed_source_blocks_.emplace(src_block_it->first);
-
- auto it = parked_packets_.find(src_block_it->first);
- if (it != parked_packets_.end()) {
- parked_packets_.erase(it);
- }
-
- src_blocks_.erase(src_block_it);
-}
-
-void decoder::consume(const fec::buffer &packet, uint32_t index) {
- // Normalize index
- auto i = index % n_;
-
- // Get base
- uint32_t base = index - i;
-
- TRANSPORT_LOGD(
- "Decoder consume called for source symbol. BASE = %u, index = %u and i = "
- "%u",
- base, index, i);
-
- // check if a source block already exist for this symbol. If it does not
- // exist, we lazily park this packet until we receive a repair symbol for the
- // same block. This is done for 2 reason:
- // 1) If we receive all the source packets of a block, we do not need to
- // recover anything.
- // 2) Sender may change n and k at any moment, so we construct the source
- // block based on the (n, k) values written in the fec header. This is
- // actually not used right now, since we use fixed value of n and k passed
- // at construction time, but it paves the ground for a more dynamic
- // protocol that may come in the future.
- auto it = src_blocks_.find(base);
- if (it != src_blocks_.end()) {
- auto ret = it->second.addSourceSymbol(packet, i);
- if (!ret) {
- recoverPackets(it);
- }
- } else {
- TRANSPORT_LOGD("Adding to parked source packets");
- auto ret = parked_packets_.emplace(
- base, std::vector<std::pair<buffer, uint32_t> >());
- ret.first->second.emplace_back(packet, i);
- }
-}
-
-void decoder::consume(const fec::buffer &packet) {
- // Repair symbol! Get index and base source block.
- fec_header *h = reinterpret_cast<fec_header *>(packet->writableData());
- auto i = h->getEncodedSymbolId();
- auto base = h->getSeqNumberBase();
- auto n = h->getSourceBlockLen();
- auto k = n - h->getNFecSymbols();
-
- TRANSPORT_LOGD(
- "Decoder consume called for repair symbol. BASE = %u, index = %u and i = "
- "%u",
- base, base + i, i);
-
- // check if a source block already exist for this symbol
- auto it = src_blocks_.find(base);
- if (it == src_blocks_.end()) {
- // Create new source block
- auto code_it = codes_.find(std::make_pair(k, n));
- if (code_it == codes_.end()) {
- TRANSPORT_LOGE("Code for k = %u and n = %u does not exist.", k_, n_);
- return;
- }
-
- auto emplace_result =
- src_blocks_.emplace(base, BlockCode(k, n, code_it->second.get()));
- it = emplace_result.first;
-
- // Check in the parked packets and insert any packet that is part of this
- // source block
-
- auto it2 = parked_packets_.find(base);
- if (it2 != parked_packets_.end()) {
- for (auto &packet_index : it2->second) {
- auto ret =
- it->second.addSourceSymbol(packet_index.first, packet_index.second);
- if (!ret) {
- recoverPackets(it);
- // Finish to delete packets in same source block that were
- // eventually not used
- return;
- }
- }
- }
- }
-
- auto ret = it->second.addRepairSymbol(packet, i);
- if (!ret) {
- recoverPackets(it);
- }
-}
-
-} // namespace fec
-} // namespace core
-} // namespace transport
diff --git a/libtransport/src/core/tcp_socket_connector.cc b/libtransport/src/core/tcp_socket_connector.cc
index fa029c6fc..a30264271 100644
--- a/libtransport/src/core/tcp_socket_connector.cc
+++ b/libtransport/src/core/tcp_socket_connector.cc
@@ -18,8 +18,8 @@
#include <hicn/transport/portability/win_portability.h>
#endif
+#include <glog/logging.h>
#include <hicn/transport/errors/errors.h>
-#include <hicn/transport/utils/log.h>
#include <hicn/transport/utils/object_pool.h>
#include <thread>
@@ -162,7 +162,7 @@ void TcpSocketConnector::doWrite() {
// The connection has been closed by the application.
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << ":" << ec.message();
tryReconnect();
}
});
@@ -182,7 +182,7 @@ void TcpSocketConnector::doReadBody(std::size_t body_length) {
// The connection has been closed by the application.
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
tryReconnect();
}
});
@@ -203,23 +203,23 @@ void TcpSocketConnector::doReadHeader() {
0) {
doReadBody(body_length - length);
} else {
- TRANSPORT_LOGE("Decoding error. Ignoring packet.");
+ LOG(ERROR) << "Decoding error. Ignoring packet.";
}
} else if (ec.value() ==
static_cast<int>(std::errc::operation_canceled)) {
// The connection has been closed by the application.
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
tryReconnect();
}
});
}
void TcpSocketConnector::tryReconnect() {
- if (state_ == ConnectorState::CONNECTED) {
- TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n");
- state_ = ConnectorState::CONNECTING;
+ if (state_ == Connector::State::CONNECTED) {
+ LOG(ERROR) << "Connection lost. Trying to reconnect...";
+ state_ = Connector::State::CONNECTING;
is_reconnection_ = true;
io_service_.post([this]() {
if (socket_.is_open()) {
@@ -250,7 +250,7 @@ void TcpSocketConnector::doConnect() {
if (is_reconnection_) {
is_reconnection_ = false;
- TRANSPORT_LOGI("Connection recovered!\n");
+ LOG(INFO) << "Connection recovered!";
on_reconnect_callback_();
}
} else {
@@ -274,7 +274,7 @@ void TcpSocketConnector::handleDeadline(const std::error_code &ec) {
if (!ec) {
io_service_.post([this]() {
socket_.close();
- TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n");
+ LOG(ERROR) << "Error connecting. Is the forwarder running?";
io_service_.stop();
});
}
diff --git a/libtransport/src/core/tcp_socket_connector.h b/libtransport/src/core/tcp_socket_connector.h
index 9dbd250d1..21db8301e 100644
--- a/libtransport/src/core/tcp_socket_connector.h
+++ b/libtransport/src/core/tcp_socket_connector.h
@@ -17,11 +17,10 @@
#include <core/connector.h>
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/name.h>
#include <hicn/transport/utils/branch_prediction.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <deque>
namespace transport {
diff --git a/libtransport/src/core/udp_socket_connector.cc b/libtransport/src/core/udp_socket_connector.cc
deleted file mode 100644
index f5ddd6270..000000000
--- a/libtransport/src/core/udp_socket_connector.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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.
- */
-
-#ifdef _WIN32
-#include <hicn/transport/portability/win_portability.h>
-#endif
-
-#include <hicn/transport/errors/errors.h>
-#include <hicn/transport/utils/log.h>
-#include <hicn/transport/utils/object_pool.h>
-
-#include <core/udp_socket_connector.h>
-
-#include <thread>
-#include <vector>
-
-namespace transport {
-
-namespace core {
-
-UdpSocketConnector::UdpSocketConnector(
- PacketReceivedCallback &&receive_callback,
- OnReconnect &&on_reconnect_callback, asio::io_service &io_service,
- std::string app_name)
- : Connector(std::move(receive_callback), std::move(on_reconnect_callback)),
- io_service_(io_service),
- socket_(io_service_),
- resolver_(io_service_),
- connection_timer_(io_service_),
- read_msg_(packet_pool_.makePtr(nullptr)),
- is_reconnection_(false),
- data_available_(false),
- app_name_(app_name) {}
-
-UdpSocketConnector::~UdpSocketConnector() {}
-
-void UdpSocketConnector::connect(std::string ip_address, std::string port) {
- endpoint_iterator_ = resolver_.resolve(
- {ip_address, port, asio::ip::resolver_query_base::numeric_service});
-
- state_ = ConnectorState::CONNECTING;
- doConnect();
-}
-
-void UdpSocketConnector::send(const uint8_t *packet, std::size_t len,
- const PacketSentCallback &packet_sent) {
- if (packet_sent != 0) {
- socket_.async_send(
- asio::buffer(packet, len),
- [packet_sent](std::error_code ec, std::size_t /*length*/) {
- packet_sent();
- });
- } else {
- if (state_ == ConnectorState::CONNECTED) {
- try {
- socket_.send(asio::buffer(packet, len));
- } catch (std::system_error &err) {
- TRANSPORT_LOGE(
- "Sending of disconnect message to forwarder failed. Reason: %s",
- err.what());
- }
- }
- }
-}
-
-void UdpSocketConnector::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_TRUE(state_ == ConnectorState::CONNECTED)) {
- if (!write_in_progress) {
- doWrite();
- }
- } else {
- // Tell the handle connect it has data to write
- data_available_ = true;
- }
- });
-}
-
-void UdpSocketConnector::close() {
- if (io_service_.stopped()) {
- doClose();
- } else {
- io_service_.dispatch(std::bind(&UdpSocketConnector::doClose, this));
- }
-}
-
-void UdpSocketConnector::doClose() {
- if (state_ != ConnectorState::CLOSED) {
- state_ = ConnectorState::CLOSED;
- if (socket_.is_open()) {
- socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both);
- socket_.close();
- }
- }
-}
-
-void UdpSocketConnector::doWrite() {
- 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](std::error_code ec,
- std::size_t length) {
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- output_buffer_.pop_front();
- if (!output_buffer_.empty()) {
- doWrite();
- }
- } else if (ec.value() == static_cast<int>(std::errc::operation_canceled)) {
- // The connection has been closed by the application.
- return;
- } else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
- tryReconnect();
- }
- });
-}
-
-void UdpSocketConnector::doRead() {
- read_msg_ = getPacket();
- socket_.async_receive(
- asio::buffer(read_msg_->writableData(), Connector::packet_size),
- [this](std::error_code ec, std::size_t length) {
- if (TRANSPORT_EXPECT_TRUE(!ec)) {
- read_msg_->append(length);
- receive_callback_(std::move(read_msg_));
- doRead();
- } else if (ec.value() ==
- static_cast<int>(std::errc::operation_canceled)) {
- // The connection has been closed by the application.
- return;
- } else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
- tryReconnect();
- }
- });
-}
-
-void UdpSocketConnector::tryReconnect() {
- if (state_ == ConnectorState::CONNECTED) {
- TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n");
- state_ = ConnectorState::CONNECTING;
- is_reconnection_ = true;
- io_service_.post([this]() {
- if (socket_.is_open()) {
- socket_.shutdown(asio::ip::tcp::socket::shutdown_type::shutdown_both);
- socket_.close();
- }
-
- doConnect();
- startConnectionTimer();
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
- });
- }
-}
-
-void UdpSocketConnector::doConnect() {
- asio::async_connect(
- socket_, endpoint_iterator_,
- [this](std::error_code ec, udp::resolver::iterator) {
- if (!ec) {
- connection_timer_.cancel();
- state_ = ConnectorState::CONNECTED;
- doRead();
-
- if (data_available_) {
- data_available_ = false;
- doWrite();
- }
-
- if (is_reconnection_) {
- is_reconnection_ = false;
- }
-
- on_reconnect_callback_();
- } else {
- doConnect();
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
- }
- });
-}
-
-bool UdpSocketConnector::checkConnected() {
- return state_ == ConnectorState::CONNECTED;
-}
-
-void UdpSocketConnector::startConnectionTimer() {
- connection_timer_.expires_from_now(std::chrono::seconds(60));
- connection_timer_.async_wait(std::bind(&UdpSocketConnector::handleDeadline,
- this, std::placeholders::_1));
-}
-
-void UdpSocketConnector::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/core/udp_socket_connector.h b/libtransport/src/core/udp_socket_connector.h
deleted file mode 100644
index 5fdb6aeec..000000000
--- a/libtransport/src/core/udp_socket_connector.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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/name.h>
-#include <hicn/transport/utils/branch_prediction.h>
-
-#include <core/connector.h>
-
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
-#include <deque>
-
-namespace transport {
-namespace core {
-
-using asio::ip::udp;
-
-class UdpSocketConnector : public Connector {
- public:
- UdpSocketConnector(PacketReceivedCallback &&receive_callback,
- OnReconnect &&reconnect_callback,
- asio::io_service &io_service,
- std::string app_name = "Libtransport");
-
- ~UdpSocketConnector() 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(std::string ip_address = "127.0.0.1", std::string port = "9695");
-
- private:
- void doConnect();
-
- void doRead();
-
- void doWrite();
-
- void doClose();
-
- bool checkConnected();
-
- private:
- void handleDeadline(const std::error_code &ec);
-
- void startConnectionTimer();
-
- void tryReconnect();
-
- asio::io_service &io_service_;
- asio::ip::udp::socket socket_;
- asio::ip::udp::resolver resolver_;
- asio::ip::udp::resolver::iterator endpoint_iterator_;
- asio::steady_timer connection_timer_;
-
- utils::ObjectPool<utils::MemBuf>::Ptr read_msg_;
-
- bool is_reconnection_;
- bool data_available_;
-
- std::string app_name_;
-};
-
-} // end namespace core
-
-} // end namespace transport
diff --git a/libtransport/src/core/vpp_forwarder_interface.cc b/libtransport/src/core/vpp_forwarder_interface.cc
deleted file mode 100644
index 9f7beeb37..000000000
--- a/libtransport/src/core/vpp_forwarder_interface.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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 <core/hicn_vapi.h>
-#include <core/memif_vapi.h>
-#include <core/vpp_forwarder_interface.h>
-
-extern "C" {
-#include <memif/libmemif.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 {
-
-VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector)
- : ForwarderInterface<VPPForwarderInterface, MemifConnector>(connector),
- sw_if_index_(~0),
- face_id1_(~0),
- face_id2_(~0),
- is_consumer_(false) {}
-
-VPPForwarderInterface::~VPPForwarderInterface() {}
-
-/**
- * @brief Create a memif interface in the local VPP forwarder.
- */
-uint32_t VPPForwarderInterface::getMemifConfiguration() {
- memif_create_params_t input_params = {0};
-
- int ret =
- memif_vapi_get_next_memif_id(VPPForwarderInterface::sock_, &memif_id_);
-
- if (ret < 0) {
- throw errors::RuntimeException(
- "Error getting next memif id. Could not create memif interface.");
- }
-
- 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};
-
- ret = memif_vapi_create_memif(VPPForwarderInterface::sock_, &input_params,
- &output_params);
-
- if (ret < 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 = {0};
- ip_address_t ip4_address;
- ip_address_t ip6_address;
-
- output.src4 = &ip4_address;
- output.src6 = &ip6_address;
- input.swif = sw_if_index_;
-
- int ret = hicn_vapi_register_cons_app(VPPForwarderInterface::sock_, &input,
- &output);
-
- if (ret < 0) {
- throw errors::RuntimeException(hicn_vapi_get_error_string(ret));
- }
-
- face_id1_ = output.face_id1;
- face_id2_ = output.face_id2;
-
- std::memcpy(inet_address_.v4.as_u8, output.src4->v4.as_u8, IPV4_ADDR_LEN);
-
- std::memcpy(inet6_address_.v6.as_u8, output.src6->v6.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) {
- int retry = 20;
-
- TRANSPORT_LOGI("Connecting to VPP through vapi.");
- vapi_error_e ret = vapi_connect_safe(&sock_, 0);
-
- while (ret != VAPI_OK && retry > 0) {
- TRANSPORT_LOGE("Error connecting to VPP through vapi. Retrying..");
- --retry;
- ret = vapi_connect_safe(&sock_, 0);
- }
-
- if (ret != VAPI_OK) {
- throw std::runtime_error(
- "Impossible to connect to forwarder. Is VPP running?");
- }
-
-
- TRANSPORT_LOGI("Connected to VPP through vapi.");
-
- sw_if_index_ = getMemifConfiguration();
-
- is_consumer_ = is_consumer;
- if (is_consumer_) {
- consumerConnection();
- }
-
- connector_.connect(memif_id_, 0);
-}
-
-void VPPForwarderInterface::registerRoute(Prefix &prefix) {
- ip_prefix_t &addr = prefix.toIpPrefixStruct();
-
- ip_prefix_t producer_prefix;
- ip_address_t producer_locator;
-
- if (face_id1_ == 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));
-
- input.prefix = &producer_prefix;
- output.prod_addr = &producer_locator;
-
- // 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->address = addr.address;
- input.prefix->family = addr.family;
- input.prefix->len = addr.len;
- input.cs_reserved = content_store_reserved_;
-
- int ret = hicn_vapi_register_prod_app(VPPForwarderInterface::sock_, &input,
- &output);
-
- if (ret < 0) {
- throw errors::RuntimeException(hicn_vapi_get_error_string(ret));
- }
-
- inet6_address_ = *output.prod_addr;
-
- face_id1_ = output.face_id;
- } else {
- hicn_producer_set_route_params params;
- params.prefix = &producer_prefix;
- params.prefix->address = addr.address;
- params.prefix->family = addr.family;
- params.prefix->len = addr.len;
- params.prod_addr = &producer_locator;
-
- int ret = hicn_vapi_register_route(VPPForwarderInterface::sock_, &params);
-
- if (ret < 0) {
- throw errors::RuntimeException(hicn_vapi_get_error_string(ret));
- }
- }
-}
-
-void VPPForwarderInterface::closeConnection() {
- if (VPPForwarderInterface::sock_) {
- connector_.close();
-
- if (is_consumer_) {
- hicn_del_face_app_input_params params;
- params.face_id = face_id1_;
- hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, &params);
- params.face_id = face_id2_;
- hicn_vapi_face_cons_del(VPPForwarderInterface::sock_, &params);
- } else {
- hicn_del_face_app_input_params params;
- params.face_id = face_id1_;
- hicn_vapi_face_prod_del(VPPForwarderInterface::sock_, &params);
- }
-
- if (sw_if_index_ != uint32_t(~0)) {
- int ret =
- memif_vapi_delete_memif(VPPForwarderInterface::sock_, sw_if_index_);
- if (ret < 0) {
- TRANSPORT_LOGE("Error deleting memif with sw idx %u.", sw_if_index_);
- }
- }
-
- vapi_disconnect_safe();
- VPPForwarderInterface::sock_ = nullptr;
- }
-}
-
-} // namespace core
-
-} // namespace transport
-
-#endif
diff --git a/libtransport/src/core/vpp_forwarder_interface.h b/libtransport/src/core/vpp_forwarder_interface.h
deleted file mode 100644
index 31d23b40d..000000000
--- a/libtransport/src/core/vpp_forwarder_interface.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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/prefix.h>
-
-
-#ifdef always_inline
-#undef always_inline
-#endif
-extern "C" {
-#include <vapi/vapi_safe.h>
-};
-
-#include <core/forwarder_interface.h>
-#include <core/memif_connector.h>
-
-#include <deque>
-
-namespace transport {
-
-namespace core {
-
-class VPPForwarderInterface
- : public ForwarderInterface<VPPForwarderInterface, MemifConnector> {
- static constexpr std::uint16_t interface_mtu = 1500;
-
- 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; }
-
- TRANSPORT_ALWAYS_INLINE static bool isControlMessageImpl(
- const uint8_t *message) {
- return false;
- }
-
- TRANSPORT_ALWAYS_INLINE void processControlMessageReplyImpl(
- Packet::MemBufPtr &&packet_buffer) {}
-
- void closeConnection();
-
- private:
- uint32_t getMemifConfiguration();
-
- void consumerConnection();
-
- void producerConnection();
-
- uint32_t memif_id_;
- uint32_t sw_if_index_;
- // A consumer socket in vpp has two faces (ipv4 and ipv6)
- uint32_t face_id1_;
- uint32_t face_id2_;
- bool is_consumer_;
- vapi_ctx_t sock_;
-};
-
-} // namespace core
-
-} // namespace transport
-
-#endif
diff --git a/libtransport/src/http/CMakeLists.txt b/libtransport/src/http/CMakeLists.txt
index 00708822d..2407faea3 100644
--- a/libtransport/src/http/CMakeLists.txt
+++ b/libtransport/src/http/CMakeLists.txt
@@ -11,8 +11,6 @@
# 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
diff --git a/libtransport/src/http/client_connection.cc b/libtransport/src/http/client_connection.cc
index a24a821e7..b4ab7cbc3 100644
--- a/libtransport/src/http/client_connection.cc
+++ b/libtransport/src/http/client_connection.cc
@@ -13,14 +13,12 @@
* limitations under the License.
*/
+#include <glog/logging.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/http/client_connection.h>
#include <hicn/transport/utils/hash.h>
-#include <hicn/transport/utils/log.h>
-
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#define DEFAULT_BETA 0.99
#define DEFAULT_GAMMA 0.07
@@ -77,13 +75,12 @@ class HTTPClientConnection::Implementation
success_callback_ = [this, method = std::move(method), url = std::move(url),
start = std::move(start)](std::size_t size) -> void {
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_.str().c_str(),
- (unsigned long long)
- std::chrono::duration_cast<std::chrono::microseconds>(end - start)
- .count(),
- size);
+ LOG(INFO) << method_map[method].c_str() << " " << url.c_str() << " ["
+ << name_.str() << "] duration: "
+ << std::chrono::duration_cast<std::chrono::microseconds>(end -
+ start)
+ .count()
+ << " [usec] " << size << " [bytes]";
};
sendRequestGetReply(ipv6_first_word);
@@ -203,8 +200,8 @@ class HTTPClientConnection::Implementation
}
void readError(const std::error_code ec) noexcept override {
- TRANSPORT_LOGE("Error %s during download of %s", ec.message().c_str(),
- current_url_.c_str());
+ LOG(ERROR) << "Error " << ec.message() << " during download of "
+ << current_url_.c_str();
if (read_bytes_callback_) {
read_bytes_callback_->onError(ec);
}
diff --git a/libtransport/src/implementation/CMakeLists.txt b/libtransport/src/implementation/CMakeLists.txt
index 392c99e15..daf899d06 100644
--- a/libtransport/src/implementation/CMakeLists.txt
+++ b/libtransport/src/implementation/CMakeLists.txt
@@ -11,8 +11,6 @@
# 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_producer.h
diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.cc b/libtransport/src/implementation/p2psecure_socket_consumer.cc
index 0b5966e71..4b14da5d2 100644
--- a/libtransport/src/implementation/p2psecure_socket_consumer.cc
+++ b/libtransport/src/implementation/p2psecure_socket_consumer.cc
@@ -251,7 +251,7 @@ int P2PSecureConsumerSocket::handshake() {
network_name_ = producer_namespace_.getRandomName();
network_name_.setSuffix(0);
- TRANSPORT_LOGD("Start handshake at %s", network_name_.toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "Start handshake at " << network_name_;
result = SSL_connect(this->ssl_);
return result;
@@ -291,7 +291,7 @@ int P2PSecureConsumerSocket::consume(const Name &name) {
if (handshake() != 1) {
throw errors::RuntimeException("Unable to perform client handshake");
} else {
- TRANSPORT_LOGD("Handshake performed!");
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
}
initSessionSocket();
@@ -320,7 +320,7 @@ int P2PSecureConsumerSocket::asyncConsume(const Name &name) {
if (handshake() != 1) {
throw errors::RuntimeException("Unable to perform client handshake");
} else {
- TRANSPORT_LOGD("Handshake performed!");
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
}
initSessionSocket();
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.cc b/libtransport/src/implementation/p2psecure_socket_producer.cc
index aa14f9e37..3748001fc 100644
--- a/libtransport/src/implementation/p2psecure_socket_producer.cc
+++ b/libtransport/src/implementation/p2psecure_socket_producer.cc
@@ -50,19 +50,8 @@ P2PSecureProducerSocket::P2PSecureProducerSocket(
map_producers(),
list_producers() {
/* Setup SSL context (identity and parameter to use TLS 1.3) */
- der_cert_ = parcKeyStore_GetDEREncodedCertificate(
- (identity->getSigner()->getParcKeyStore()));
- der_prk_ = parcKeyStore_GetDEREncodedPrivateKey(
- (identity->getSigner()->getParcKeyStore()));
-
- int cert_size = (int)parcBuffer_Limit(der_cert_);
- int prk_size = (int)parcBuffer_Limit(der_prk_);
- const uint8_t *cert =
- reinterpret_cast<uint8_t *>(parcBuffer_Overlay(der_cert_, cert_size));
- const uint8_t *prk =
- reinterpret_cast<uint8_t *>(parcBuffer_Overlay(der_prk_, prk_size));
- cert_509_ = d2i_X509(NULL, &cert, cert_size);
- pkey_rsa_ = d2i_AutoPrivateKey(NULL, &prk, prk_size);
+ cert_509_ = identity->getCertificate().get();
+ pkey_rsa_ = identity->getPrivateKey().get();
/* Set the callback so that when an interest is received we catch it and we
* decrypt the payload before passing it to the application. */
@@ -73,10 +62,7 @@ P2PSecureProducerSocket::P2PSecureProducerSocket(
std::placeholders::_1, std::placeholders::_2));
}
-P2PSecureProducerSocket::~P2PSecureProducerSocket() {
- if (der_cert_) parcBuffer_Release(&der_cert_);
- if (der_prk_) parcBuffer_Release(&der_prk_);
-}
+P2PSecureProducerSocket::~P2PSecureProducerSocket() {}
void P2PSecureProducerSocket::initSessionSocket(
std::unique_ptr<TLSProducerSocket> &producer) {
@@ -128,8 +114,7 @@ void P2PSecureProducerSocket::onInterestCallback(interface::ProducerSocket &p,
TLSProducerSocket *tls_producer_ptr = tls_producer.get();
map_producers.insert({interest.getName(), move(tls_producer)});
- TRANSPORT_LOGD("Start handshake at %s",
- interest.getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Start handshake at " << interest.getName();
if (!rtc_) {
tls_producer_ptr->onInterest(*tls_producer_ptr, interest);
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.h b/libtransport/src/implementation/p2psecure_socket_producer.h
index b7c3d1958..f94347258 100644
--- a/libtransport/src/implementation/p2psecure_socket_producer.h
+++ b/libtransport/src/implementation/p2psecure_socket_producer.h
@@ -103,8 +103,6 @@ class P2PSecureProducerSocket : public ProducerSocket {
std::mutex mtx_;
/* Condition variable for the wait */
std::condition_variable cv_;
- PARCBuffer *der_cert_;
- PARCBuffer *der_prk_;
X509 *cert_509_;
EVP_PKEY *pkey_rsa_;
std::unordered_map<core::Name, std::unique_ptr<TLSProducerSocket>,
diff --git a/libtransport/src/implementation/rtc_socket_producer.cc b/libtransport/src/implementation/rtc_socket_producer.cc
deleted file mode 100644
index a5b2b4a0e..000000000
--- a/libtransport/src/implementation/rtc_socket_producer.cc
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * 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/callbacks.h>
-
-#include <implementation/rtc_socket_producer.h>
-#include <stdlib.h>
-#include <time.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
-#define INACTIVE_TIME \
- 500 // ms without producing before the socket
- // is considered inactive
-#define MILLI_IN_A_SEC 1000 // ms in a second
-
-#define HICN_MAX_DATA_SEQ 0xefffffff
-
-// slow production rate param
-#define MIN_PRODUCTION_RATE \
- 10 // in pacekts per sec. this value is computed
- // through experiments
-#define LIFETIME_FRACTION 0.5
-
-// NACK HEADER
-// +-----------------------------------------+
-// | 4 bytes: current segment in production |
-// +-----------------------------------------+
-// | 4 bytes: production rate (bytes x sec) |
-// +-----------------------------------------+
-//
-
-// PACKET HEADER
-// +-----------------------------------------+
-// | 8 bytes: TIMESTAMP |
-// +-----------------------------------------+
-// | packet |
-// +-----------------------------------------+
-
-namespace transport {
-namespace implementation {
-
-RTCProducerSocket::RTCProducerSocket(interface::ProducerSocket *producer_socket)
- : ProducerSocket(producer_socket),
- currentSeg_(1),
- producedBytes_(0),
- producedPackets_(0),
- bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400),
- packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE),
- perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION),
- timer_on_(false) {
- srand((unsigned int)time(NULL));
- prodLabel_ = ((rand() % 255) << 24UL);
- interests_cache_timer_ =
- std::make_unique<asio::steady_timer>(this->getIoService());
- round_timer_ = std::make_unique<asio::steady_timer>(this->getIoService());
- setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U);
- scheduleRoundTimer();
-}
-
-RTCProducerSocket::~RTCProducerSocket() {}
-
-void RTCProducerSocket::registerPrefix(const Prefix &producer_namespace) {
- ProducerSocket::registerPrefix(producer_namespace);
-
- flowName_ = producer_namespace.getName();
- auto family = flowName_.getAddressFamily();
-
- switch (family) {
- case AF_INET6:
- headerSize_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET6_TCP);
- break;
- case AF_INET:
- headerSize_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET_TCP);
- break;
- default:
- throw errors::RuntimeException("Unknown name format.");
- }
-}
-
-void RTCProducerSocket::scheduleRoundTimer() {
- round_timer_->expires_from_now(
- std::chrono::milliseconds(STATS_INTERVAL_DURATION));
- round_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- updateStats();
- });
-}
-
-void RTCProducerSocket::updateStats() {
- bytesProductionRate_ = producedBytes_.load() * perSecondFactor_;
- packetsProductionRate_ = producedPackets_.load() * perSecondFactor_;
- if (packetsProductionRate_.load() == 0) packetsProductionRate_ = 1;
- producedBytes_ = 0;
- producedPackets_ = 0;
- scheduleRoundTimer();
-}
-
-void RTCProducerSocket::produce(std::unique_ptr<utils::MemBuf> &&buffer) {
- auto buffer_size = buffer->length();
-
- if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) {
- return;
- }
-
- if (TRANSPORT_EXPECT_FALSE((buffer_size + headerSize_ + TIMESTAMP_LEN) >
- data_packet_size_)) {
- return;
- }
-
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- producedBytes_ += (uint32_t)(buffer_size + headerSize_ + TIMESTAMP_LEN);
- producedPackets_++;
-
- Name n(flowName_);
- auto content_object =
- std::make_shared<ContentObject>(n.setSuffix(currentSeg_.load()));
- auto payload = utils::MemBuf::create(TIMESTAMP_LEN);
-
- memcpy(payload->writableData(), &now, TIMESTAMP_LEN);
- payload->append(TIMESTAMP_LEN);
- payload->prependChain(std::move(buffer));
- content_object->appendPayload(std::move(payload));
-
- content_object->setLifetime(500); // XXX this should be set by the APP
-
- content_object->setPathLabel(prodLabel_);
-
- output_buffer_.insert(std::static_pointer_cast<ContentObject>(
- content_object->shared_from_this()));
-
- if (on_content_object_in_output_buffer_) {
- on_content_object_in_output_buffer_(*getInterface(), *content_object);
- }
-
- TRANSPORT_LOGD("Send content %u (produce)",
- content_object->getName().getSuffix());
- portal_->sendContentObject(*content_object);
-
- if (on_content_object_output_) {
- on_content_object_output_(*getInterface(), *content_object);
- }
-
- uint32_t old_curr = currentSeg_.load();
- currentSeg_ = (currentSeg_.load() + 1) % HICN_MAX_DATA_SEQ;
-
- // remove interests from the interest cache if it exists
- // this generates nacks that will tell to the consumer
- // that a new data packet was produced
- utils::SpinLock::Acquire locked(interests_cache_lock_);
- if (!seqs_map_.empty()) {
- for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) {
- if (it->first != old_curr) sendNack(it->first);
- }
- seqs_map_.clear();
- timers_map_.clear();
- }
-}
-
-void RTCProducerSocket::onInterest(Interest::Ptr &&interest) {
- uint32_t interestSeg = interest->getName().getSuffix();
- uint32_t lifetime = interest->getLifetime();
-
- if (on_interest_input_) {
- on_interest_input_(*getInterface(), *interest);
- }
-
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- if (interestSeg > HICN_MAX_DATA_SEQ) {
- sendNack(interestSeg);
- return;
- }
-
- const std::shared_ptr<ContentObject> content_object =
- output_buffer_.find(*interest);
-
- if (content_object) {
- if (on_interest_satisfied_output_buffer_) {
- on_interest_satisfied_output_buffer_(*getInterface(), *interest);
- }
-
- if (on_content_object_output_) {
- on_content_object_output_(*getInterface(), *content_object);
- }
-
- TRANSPORT_LOGD("Send content %u (onInterest)",
- content_object->getName().getSuffix());
- portal_->sendContentObject(*content_object);
- return;
- } else {
- if (on_interest_process_) {
- on_interest_process_(*getInterface(), *interest);
- }
- }
-
- // if the production rate is less than MIN_PRODUCTION_RATE we put the
- // interest in a queue, otherwise we handle it in the usual way
- if (packetsProductionRate_.load() < MIN_PRODUCTION_RATE &&
- interestSeg >= currentSeg_.load()) {
- utils::SpinLock::Acquire locked(interests_cache_lock_);
-
- uint64_t next_timer = ~0;
- if (!timers_map_.empty()) {
- next_timer = timers_map_.begin()->first;
- }
-
- uint64_t expiration = now + (lifetime * LIFETIME_FRACTION);
- // check if the seq number exists already
- auto it_seqs = seqs_map_.find(interestSeg);
- if (it_seqs != seqs_map_.end()) {
- // the seq already exists
- if (expiration < it_seqs->second) {
- // we need to update the timer becasue we got a smaller one
- // 1) remove the entry from the multimap
- // 2) update this entry
- auto range = timers_map_.equal_range(it_seqs->second);
- for (auto it_timers = range.first; it_timers != range.second;
- it_timers++) {
- if (it_timers->second == it_seqs->first) {
- timers_map_.erase(it_timers);
- break;
- }
- }
- timers_map_.insert(
- std::pair<uint64_t, uint32_t>(expiration, interestSeg));
- it_seqs->second = expiration;
- } else {
- // nothing to do here
- return;
- }
- } else {
- // add the new seq
- timers_map_.insert(
- std::pair<uint64_t, uint32_t>(expiration, interestSeg));
- seqs_map_.insert(std::pair<uint32_t, uint64_t>(interestSeg, expiration));
- }
-
- // here we have at least one interest in the queue, we need to start or
- // update the timer
- if (!timer_on_) {
- // set timeout
- timer_on_ = true;
- scheduleCacheTimer(timers_map_.begin()->first - now);
- } else {
- // re-schedule the timer because a new interest will expires sooner
- if (next_timer > timers_map_.begin()->first) {
- interests_cache_timer_->cancel();
- scheduleCacheTimer(timers_map_.begin()->first - now);
- }
- }
- return;
- }
-
- uint32_t max_gap = (uint32_t)floor(
- (double)((double)((double)lifetime * INTEREST_LIFETIME_REDUCTION_FACTOR /
- 1000.0) *
- (double)packetsProductionRate_.load()));
-
- if (interestSeg < currentSeg_.load() ||
- interestSeg > (max_gap + currentSeg_.load())) {
- sendNack(interestSeg);
- }
- // else drop packet
-}
-
-void RTCProducerSocket::scheduleCacheTimer(uint64_t wait) {
- interests_cache_timer_->expires_from_now(std::chrono::milliseconds(wait));
- interests_cache_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- interestCacheTimer();
- });
-}
-
-void RTCProducerSocket::interestCacheTimer() {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- utils::SpinLock::Acquire locked(interests_cache_lock_);
-
- for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) {
- uint64_t expire = it_timers->first;
- if (expire <= now) {
- uint32_t seq = it_timers->second;
- sendNack(seq);
- // remove the interest from the other map
- seqs_map_.erase(seq);
- it_timers = timers_map_.erase(it_timers);
- } else {
- // stop, we are done!
- break;
- }
- }
- if (timers_map_.empty()) {
- timer_on_ = false;
- } else {
- timer_on_ = true;
- scheduleCacheTimer(timers_map_.begin()->first - now);
- }
-}
-
-void RTCProducerSocket::sendNack(uint32_t sequence) {
- auto nack_payload = utils::MemBuf::create(NACK_HEADER_SIZE);
- nack_payload->append(NACK_HEADER_SIZE);
- ContentObject nack;
-
- Name n(flowName_);
- nack.appendPayload(std::move(nack_payload));
- nack.setName(n.setSuffix(sequence));
-
- uint32_t *payload_ptr = (uint32_t *)nack.getPayload()->data();
- *payload_ptr = currentSeg_.load();
-
- *(++payload_ptr) = bytesProductionRate_.load();
-
- nack.setLifetime(0);
- nack.setPathLabel(prodLabel_);
-
- if (on_content_object_output_) {
- on_content_object_output_(*getInterface(), nack);
- }
-
- TRANSPORT_LOGD("Send nack %u", sequence);
- portal_->sendContentObject(nack);
-}
-
-} // namespace implementation
-
-} // end namespace transport
diff --git a/libtransport/src/implementation/rtc_socket_producer.h b/libtransport/src/implementation/rtc_socket_producer.h
deleted file mode 100644
index 87db2121d..000000000
--- a/libtransport/src/implementation/rtc_socket_producer.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 <implementation/socket_producer.h>
-#include <utils/content_store.h>
-
-#include <atomic>
-#include <map>
-#include <mutex>
-
-namespace transport {
-namespace implementation {
-
-class RTCProducerSocket : virtual public ProducerSocket {
- public:
- RTCProducerSocket(interface::ProducerSocket *producer_socket);
-
- ~RTCProducerSocket();
-
- void registerPrefix(const Prefix &producer_namespace) override;
- void produce(std::unique_ptr<utils::MemBuf> &&buffer) override;
-
- private:
- void onInterest(Interest::Ptr &&interest) override;
- void sendNack(uint32_t sequence);
- void updateStats();
- void scheduleCacheTimer(uint64_t wait);
- void scheduleRoundTimer();
- void interestCacheTimer();
-
- std::atomic<uint32_t> currentSeg_;
- uint32_t prodLabel_;
- uint16_t headerSize_;
- Name flowName_;
- std::atomic<uint32_t> producedBytes_;
- std::atomic<uint32_t> producedPackets_;
- std::atomic<uint32_t> bytesProductionRate_;
- std::atomic<uint32_t> packetsProductionRate_;
- uint32_t perSecondFactor_;
-
- std::unique_ptr<asio::steady_timer> round_timer_;
-
- // cache for the received interests
- // this map maps the expiration time of an interest to
- // its sequence number. the map is sorted by timeouts
- // the same timeout may be used for multiple sequence numbers
- // but for each sequence number we store only the smallest
- // expiry time. In this way the mapping from seqs_map_ to
- // timers_map_ is unique
- std::multimap<uint64_t, uint32_t> timers_map_;
- // this map does the opposite, this map is not ordered
- std::unordered_map<uint32_t, uint64_t> seqs_map_;
- bool timer_on_;
- std::unique_ptr<asio::steady_timer> interests_cache_timer_;
- utils::SpinLock interests_cache_lock_;
-};
-
-} // namespace implementation
-
-} // end namespace transport
diff --git a/libtransport/src/implementation/socket_consumer.h b/libtransport/src/implementation/socket_consumer.h
index a7b6ac4e7..e0981af7f 100644
--- a/libtransport/src/implementation/socket_consumer.h
+++ b/libtransport/src/implementation/socket_consumer.h
@@ -15,10 +15,10 @@
#pragma once
+#include <hicn/transport/auth/verifier.h>
#include <hicn/transport/interfaces/socket_consumer.h>
#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/interfaces/statistics.h>
-#include <hicn/transport/auth/verifier.h>
#include <hicn/transport/utils/event_thread.h>
#include <protocols/cbr.h>
#include <protocols/raaqm.h>
@@ -777,7 +777,7 @@ class ConsumerSocket : public Socket {
// Verification parameters
std::shared_ptr<auth::Verifier> verifier_;
- PARCKeyId *key_id_;
+ transport::auth::KeyId *key_id_;
std::atomic_bool verify_signature_;
bool reset_window_;
diff --git a/libtransport/src/implementation/socket_producer.h b/libtransport/src/implementation/socket_producer.h
index f511f7743..9daf79b9d 100644
--- a/libtransport/src/implementation/socket_producer.h
+++ b/libtransport/src/implementation/socket_producer.h
@@ -51,7 +51,7 @@ class ProducerSocket : public Socket {
content_object_expiry_time_(default_values::content_object_expiry_time),
async_thread_(),
making_manifest_(false),
- hash_algorithm_(auth::CryptoHashType::SHA_256),
+ hash_algorithm_(auth::CryptoHashType::SHA256),
suffix_strategy_(core::NextSegmentCalculationStrategy::INCREMENTAL),
on_interest_input_(VOID_HANDLER),
on_interest_dropped_input_buffer_(VOID_HANDLER),
@@ -417,7 +417,7 @@ class ProducerSocket : public Socket {
uint32_t &socket_option_value) {
switch (socket_option_key) {
case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
- socket_option_value = (uint32_t)production_protocol_->getOutputBufferSize();
+ socket_option_value = production_protocol_->getOutputBufferSize();
break;
case GeneralTransportOptions::DATA_PACKET_SIZE:
diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.cc b/libtransport/src/implementation/tls_rtc_socket_producer.cc
index 9a62c8683..db62b10c1 100644
--- a/libtransport/src/implementation/tls_rtc_socket_producer.cc
+++ b/libtransport/src/implementation/tls_rtc_socket_producer.cc
@@ -156,7 +156,7 @@ void TLSRTCProducerSocket::accept() {
throw errors::RuntimeException("Unable to perform client handshake");
}
- TRANSPORT_LOGD("Handshake performed!");
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
parent_->list_producers.push_front(
std::move(parent_->map_producers[handshake_name_]));
diff --git a/libtransport/src/implementation/tls_socket_producer.cc b/libtransport/src/implementation/tls_socket_producer.cc
index dd92e58cf..3992ca45c 100644
--- a/libtransport/src/implementation/tls_socket_producer.cc
+++ b/libtransport/src/implementation/tls_socket_producer.cc
@@ -48,13 +48,13 @@ int TLSProducerSocket::readOld(BIO *b, char *buf, int size) {
std::unique_lock<std::mutex> lck(socket->mtx_);
- TRANSPORT_LOGD("Start wait on the CV.");
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Start wait on the CV.";
if (!socket->something_to_read_) {
(socket->cv_).wait(lck);
}
- TRANSPORT_LOGD("CV unlocked.");
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "CV unlocked.";
/* Either there already is something to read, or the thread has been waken up.
* We must return the payload in the interest anyway */
@@ -253,7 +253,7 @@ void TLSProducerSocket::accept() {
}
handshake_state_ = SERVER_FINISHED;
- TRANSPORT_LOGD("Handshake performed!");
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
}
int TLSProducerSocket::async_accept() {
@@ -305,7 +305,7 @@ void TLSProducerSocket::cacheMiss(interface::ProducerSocket &p,
Interest &interest) {
HandshakeState handshake_state = getHandshakeState();
- TRANSPORT_LOGD("On cache miss in TLS socket producer.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "On cache miss in TLS socket producer.";
if (handshake_state == CLIENT_HELLO) {
std::unique_lock<std::mutex> lck(mtx_);
@@ -390,7 +390,8 @@ int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type,
void *add_arg) {
TLSProducerSocket *socket = reinterpret_cast<TLSProducerSocket *>(add_arg);
- TRANSPORT_LOGD("On addHicnKeyIdCb, for the prefix registration.");
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "On addHicnKeyIdCb, for the prefix registration.";
if (ext_type == 100) {
auto &prefix =
diff --git a/libtransport/src/interfaces/CMakeLists.txt b/libtransport/src/interfaces/CMakeLists.txt
index 0284aa412..7ec024fec 100644
--- a/libtransport/src/interfaces/CMakeLists.txt
+++ b/libtransport/src/interfaces/CMakeLists.txt
@@ -11,8 +11,6 @@
# 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}/socket_producer.cc
${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc
diff --git a/libtransport/src/interfaces/global_configuration.cc b/libtransport/src/interfaces/global_configuration.cc
index 8fb6601f3..cecdacc07 100644
--- a/libtransport/src/interfaces/global_configuration.cc
+++ b/libtransport/src/interfaces/global_configuration.cc
@@ -14,8 +14,8 @@
*/
#include <core/global_configuration.h>
+#include <glog/logging.h>
#include <hicn/transport/interfaces/global_conf_interface.h>
-#include <hicn/transport/utils/log.h>
#include <system_error>
@@ -32,7 +32,7 @@ void ConfigurationObject::get() {
core::GlobalConfiguration::getInstance().getConfiguration(*this, ec);
if (ec) {
- TRANSPORT_LOGE("Error setting global config: %s", ec.message().c_str());
+ LOG(ERROR) << "Error setting global config: " << ec.message();
}
}
@@ -41,7 +41,7 @@ void ConfigurationObject::set() {
core::GlobalConfiguration::getInstance().setConfiguration(*this, ec);
if (ec) {
- TRANSPORT_LOGE("Error setting global config: %s", ec.message().c_str());
+ LOG(ERROR) << "Error setting global config: " << ec.message();
}
}
diff --git a/libtransport/src/interfaces/portal.cc b/libtransport/src/interfaces/portal.cc
index 2ab51c4b9..9db0621f6 100644
--- a/libtransport/src/interfaces/portal.cc
+++ b/libtransport/src/interfaces/portal.cc
@@ -94,4 +94,4 @@ void Portal::registerRoute(core::Prefix &prefix) {
} // namespace interface
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/io_modules/CMakeLists.txt b/libtransport/src/io_modules/CMakeLists.txt
index cf466721f..29aec236a 100644
--- a/libtransport/src/io_modules/CMakeLists.txt
+++ b/libtransport/src/io_modules/CMakeLists.txt
@@ -11,10 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
-if (${CMAKE_SYSTEM_NAME} MATCHES "^(iOS|Android|Windows)$")
-
+if (${CMAKE_SYSTEM_NAME} MATCHES Android)
list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/udp/hicn_forwarder_module.cc
${CMAKE_CURRENT_SOURCE_DIR}/udp/udp_socket_connector.cc
@@ -27,7 +24,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "^(iOS|Android|Windows)$")
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
-else ()
+else()
add_subdirectory(udp)
add_subdirectory(loopback)
add_subdirectory(forwarder)
diff --git a/libtransport/src/io_modules/forwarder/CMakeLists.txt b/libtransport/src/io_modules/forwarder/CMakeLists.txt
index 92662bc4c..a1d0c5db5 100644
--- a/libtransport/src/io_modules/forwarder/CMakeLists.txt
+++ b/libtransport/src/io_modules/forwarder/CMakeLists.txt
@@ -11,9 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
-
list(APPEND MODULE_HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/connector.h
${CMAKE_CURRENT_SOURCE_DIR}/endpoint.h
@@ -37,7 +34,7 @@ build_module(forwarder_module
SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}-io-modules
INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
COMPILE_OPTIONS ${COMPILE_FLAGS}
diff --git a/libtransport/src/io_modules/forwarder/forwarder.cc b/libtransport/src/io_modules/forwarder/forwarder.cc
index 7e89e2f9f..0546cb8b3 100644
--- a/libtransport/src/io_modules/forwarder/forwarder.cc
+++ b/libtransport/src/io_modules/forwarder/forwarder.cc
@@ -15,6 +15,7 @@
#include <core/global_configuration.h>
#include <core/local_connector.h>
+#include <glog/logging.h>
#include <io_modules/forwarder/forwarder.h>
#include <io_modules/forwarder/global_id_counter.h>
#include <io_modules/forwarder/udp_tunnel.h>
@@ -127,7 +128,7 @@ void Forwarder::onPacketFromListener(Connector *connector,
std::bind(&Forwarder::onPacketReceived, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3));
- TRANSPORT_LOGD("Packet received from listener.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Packet received from listener.";
{
utils::SpinLock::Acquire locked(connector_lock_);
@@ -157,10 +158,8 @@ void Forwarder::onPacketReceived(Connector *connector,
if ((is_producer && is_interest) || (!is_producer && !is_interest)) {
c.second->send(*packet);
} else {
- TRANSPORT_LOGD(
- "Error sending packet to local connector. is_interest = %d - "
- "is_producer = %d",
- (int)is_interest, (int)is_producer);
+ LOG(ERROR) << "Error sending packet to local connector. is_interest = "
+ << is_interest << " - is_producer = " << is_producer;
}
}
@@ -178,9 +177,9 @@ void Forwarder::send(Packet &packet) {
auto remote_endpoint =
remote_connectors_.begin()->second->getRemoteEndpoint();
- TRANSPORT_LOGD("Sending packet to: %s:%u",
- remote_endpoint.getAddress().to_string().c_str(),
- remote_endpoint.getPort());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Sending packet to: " << remote_endpoint.getAddress() << ":"
+ << remote_endpoint.getPort();
remote_connectors_.begin()->second->send(packet);
}
@@ -199,7 +198,7 @@ void Forwarder::parseForwarderConfiguration(
// Get number of threads
int n_threads = 1;
forwarder_config.lookupValue("n_threads", n_threads);
- TRANSPORT_LOGD("Forwarder threads from config file: %u", n_threads);
+ VLOG(1) << "Forwarder threads from config file: " << n_threads;
config_.setThreadNumber(n_threads);
}
@@ -219,8 +218,8 @@ void Forwarder::parseForwarderConfiguration(
listener.lookupValue("local_port", port);
list.port = (uint16_t)(port);
- TRANSPORT_LOGD("Adding listener %s, (%s:%u)", list.name.c_str(),
- list.address.c_str(), list.port);
+ VLOG(1) << "Adding listener " << list.name << ", ( " << list.address
+ << ":" << list.port << ")";
config_.addListener(std::move(list));
}
}
@@ -262,9 +261,9 @@ void Forwarder::parseForwarderConfiguration(
conn.remote_port = (uint16_t)(port);
- TRANSPORT_LOGD("Adding connector %s, (%s:%u %s:%u)", conn.name.c_str(),
- conn.local_address.c_str(), conn.local_port,
- conn.remote_address.c_str(), conn.remote_port);
+ VLOG(1) << "Adding connector " << conn.name << ", (" << conn.local_address
+ << ":" << conn.local_port << " " << conn.remote_address << ":"
+ << conn.remote_port << ")";
config_.addConnector(std::move(conn));
}
}
@@ -285,8 +284,8 @@ void Forwarder::parseForwarderConfiguration(
route.lookupValue("connector", r.connector);
r.weight = (uint16_t)(weight);
- TRANSPORT_LOGD("Adding route %s %s (%s %u)", r.name.c_str(),
- r.prefix.c_str(), r.connector.c_str(), r.weight);
+ VLOG(1) << "Adding route " << r.name << " " << r.prefix << " ("
+ << r.connector << " " << r.weight << ")";
config_.addRoute(std::move(r));
}
}
diff --git a/libtransport/src/io_modules/forwarder/forwarder_module.cc b/libtransport/src/io_modules/forwarder/forwarder_module.cc
index 356b42d3b..4f95b9ca0 100644
--- a/libtransport/src/io_modules/forwarder/forwarder_module.cc
+++ b/libtransport/src/io_modules/forwarder/forwarder_module.cc
@@ -13,8 +13,8 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/errors/not_implemented_exception.h>
-#include <hicn/transport/utils/log.h>
#include <io_modules/forwarder/forwarder_module.h>
namespace transport {
@@ -36,8 +36,8 @@ bool ForwarderModule::isConnected() { return true; }
void ForwarderModule::send(Packet &packet) {
IoModule::send(packet);
forwarder_.send(packet);
- // TRANSPORT_LOGD("ForwarderModule: sending from %u to %d", local_id_,
- // 1 - local_id_);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Sending from " << connector_id_ << " to " << 1 - connector_id_;
// local_faces_.at(1 - local_id_).onPacket(packet);
}
diff --git a/libtransport/src/io_modules/forwarder/global_id_counter.h b/libtransport/src/io_modules/forwarder/global_id_counter.h
index fe8d76730..0a67b76d5 100644
--- a/libtransport/src/io_modules/forwarder/global_id_counter.h
+++ b/libtransport/src/io_modules/forwarder/global_id_counter.h
@@ -15,6 +15,8 @@
#pragma once
+#include <hicn/transport/utils/singleton.h>
+
#include <atomic>
#include <mutex>
@@ -23,32 +25,15 @@ namespace transport {
namespace core {
template <typename T = uint64_t>
-class GlobalCounter {
+class GlobalCounter : public utils::Singleton<GlobalCounter<T>> {
public:
- static GlobalCounter& getInstance() {
- std::lock_guard<std::mutex> lock(global_mutex_);
-
- if (!instance_) {
- instance_.reset(new GlobalCounter());
- }
-
- return *instance_;
- }
-
+ friend class utils::Singleton<GlobalCounter>;
T getNext() { return counter_++; }
private:
GlobalCounter() : counter_(0) {}
- static std::unique_ptr<GlobalCounter<T>> instance_;
- static std::mutex global_mutex_;
std::atomic<T> counter_;
};
-template <typename T>
-std::unique_ptr<GlobalCounter<T>> GlobalCounter<T>::instance_ = nullptr;
-
-template <typename T>
-std::mutex GlobalCounter<T>::global_mutex_;
-
} // namespace core
} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel.cc b/libtransport/src/io_modules/forwarder/udp_tunnel.cc
index dc725fc4e..bf6a69b92 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel.cc
+++ b/libtransport/src/io_modules/forwarder/udp_tunnel.cc
@@ -2,6 +2,7 @@
* Copyright (c) 2017-2019 Cisco and/or its affiliates.
*/
+#include <glog/logging.h>
#include <hicn/transport/utils/branch_prediction.h>
#include <io_modules/forwarder/errors.h>
#include <io_modules/forwarder/udp_tunnel.h>
@@ -62,7 +63,7 @@ void UdpTunnelConnector::send(Packet &packet) {
void UdpTunnelConnector::send(const uint8_t *packet, std::size_t len) {}
void UdpTunnelConnector::close() {
- TRANSPORT_LOGD("UDPTunnelConnector::close");
+ DLOG_IF(INFO, VLOG_IS_ON(2)) << "UDPTunnelConnector::close";
state_ = State::CLOSED;
bool is_socket_owned = socket_.use_count() == 1;
if (is_socket_owned) {
@@ -150,8 +151,8 @@ void UdpTunnelConnector::writeHandler(std::error_code ec) {
output_buffer_.pop_front();
}
} else if (retval != EWOULDBLOCK && retval != EAGAIN) {
- TRANSPORT_LOGE("Error sending messages! %s %d\n", strerror(errno),
- retval);
+ LOG(ERROR) << "Error sending messages! " << strerror(errno)
+ << " << retval";
return;
}
}
@@ -164,9 +165,8 @@ void UdpTunnelConnector::writeHandler(std::error_code ec) {
}
void UdpTunnelConnector::readHandler(std::error_code ec) {
- TRANSPORT_LOGD("UdpTunnelConnector receive packet");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
- // TRANSPORT_LOGD("UdpTunnelConnector received packet length=%lu", length);
if (TRANSPORT_EXPECT_TRUE(!ec)) {
if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
if (current_position_ == 0) {
@@ -182,8 +182,8 @@ void UdpTunnelConnector::readHandler(std::error_code ec) {
int res = recvmmsg(socket_->native_handle(), rx_msgs_ + current_position_,
max_burst - current_position_, MSG_DONTWAIT, nullptr);
if (res < 0) {
- TRANSPORT_LOGE("Error receiving messages! %s %d\n", strerror(errno),
- res);
+ LOG(ERROR) << "Error receiving messages! " << strerror(errno) << " "
+ << res;
return;
}
@@ -200,19 +200,20 @@ void UdpTunnelConnector::readHandler(std::error_code ec) {
doRecvPacket();
} else {
- TRANSPORT_LOGE(
- "Error in UDP: Receiving packets from a not connected socket.");
+ LOG(ERROR)
+ << "Error in UDP: Receiving packets from a not connected socket.";
}
} else if (ec.value() == static_cast<int>(std::errc::operation_canceled)) {
- TRANSPORT_LOGE("The connection has been closed by the application.");
+ LOG(ERROR) << "The connection has been closed by the application.";
return;
} else {
if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
// receive_callback_(this, *read_msg_, ec);
- TRANSPORT_LOGE("Error in UDP connector: %d %s", ec.value(),
- ec.message().c_str());
+ LOG(ERROR) << "Error in UDP connector: " << ec.value() << " "
+ << ec.message();
} else {
- TRANSPORT_LOGE("Error while not connector");
+ LOG(ERROR) << "Error in connector while not connected. " << ec.value()
+ << " " << ec.message();
}
}
}
@@ -226,16 +227,17 @@ void UdpTunnelConnector::doRecvPacket() {
#else
socket_->async_wait(asio::ip::tcp::socket::wait_read,
#endif
- std::bind(&UdpTunnelConnector::readHandler, this,
- std::placeholders::_1));
+ std::bind(&UdpTunnelConnector::readHandler, this,
+ std::placeholders::_1));
}
#else
- TRANSPORT_LOGD("UdpTunnelConnector receive packet");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
read_msg_ = getRawBuffer();
socket_->async_receive_from(
asio::buffer(read_msg_.first, read_msg_.second), remote_endpoint_recv_,
[this](std::error_code ec, std::size_t length) {
- TRANSPORT_LOGD("UdpTunnelConnector received packet length=%lu", length);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "UdpTunnelConnector received packet length=" << length;
if (TRANSPORT_EXPECT_TRUE(!ec)) {
if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
auto packet = getPacketFromBuffer(read_msg_.first, length);
@@ -244,19 +246,19 @@ void UdpTunnelConnector::doRecvPacket() {
make_error_code(forwarder_error::success));
doRecvPacket();
} else {
- TRANSPORT_LOGE(
- "Error in UDP: Receiving packets from a not connected socket.");
+ LOG(ERROR) << "Error in UDP: Receiving packets from a not "
+ "connected socket.";
}
} else if (ec.value() ==
static_cast<int>(std::errc::operation_canceled)) {
- TRANSPORT_LOGE("The connection has been closed by the application.");
+ LOG(ERROR) << "The connection has been closed by the application.";
return;
} else {
if (TRANSPORT_EXPECT_TRUE(state_ == State::CONNECTED)) {
- TRANSPORT_LOGE("Error in UDP connector: %d %s", ec.value(),
- ec.message().c_str());
+ LOG(ERROR) << "Error in UDP connector: " << ec.value()
+ << ec.message();
} else {
- TRANSPORT_LOGE("Error while not connector");
+ LOG(ERROR) << "Error while not connected";
}
}
});
@@ -276,7 +278,7 @@ void UdpTunnelConnector::doConnect() {
doSendPacket();
}
} else {
- TRANSPORT_LOGE("[Hproxy] - UDP Connection failed!!!");
+ LOG(ERROR) << "UDP Connection failed!!!";
timer_.expires_from_now(std::chrono::milliseconds(500));
timer_.async_wait(std::bind(&UdpTunnelConnector::doConnect, this));
}
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel.h b/libtransport/src/io_modules/forwarder/udp_tunnel.h
index df472af91..4f044f93f 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel.h
+++ b/libtransport/src/io_modules/forwarder/udp_tunnel.h
@@ -4,12 +4,11 @@
#pragma once
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/portability/platform.h>
#include <io_modules/forwarder/errors.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <iostream>
#include <memory>
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc b/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc
index 12246c3cf..d047cc568 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc
+++ b/libtransport/src/io_modules/forwarder/udp_tunnel_listener.cc
@@ -2,8 +2,8 @@
* Copyright (c) 2017-2019 Cisco and/or its affiliates.
*/
+#include <glog/logging.h>
#include <hicn/transport/utils/hash.h>
-#include <hicn/transport/utils/log.h>
#include <io_modules/forwarder/udp_tunnel.h>
#include <io_modules/forwarder/udp_tunnel_listener.h>
@@ -36,9 +36,8 @@ void UdpTunnelListener::close() {
#ifdef LINUX
void UdpTunnelListener::readHandler(std::error_code ec) {
- TRANSPORT_LOGD("UdpTunnelConnector receive packet");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "UdpTunnelConnector receive packet";
- // TRANSPORT_LOGD("UdpTunnelConnector received packet length=%lu", length);
if (TRANSPORT_EXPECT_TRUE(!ec)) {
if (current_position_ == 0) {
for (int i = 0; i < Connector::max_burst; i++) {
@@ -56,7 +55,8 @@ void UdpTunnelListener::readHandler(std::error_code ec) {
Connector::max_burst - current_position_, MSG_DONTWAIT,
nullptr);
if (res < 0) {
- TRANSPORT_LOGE("Error in recvmmsg.");
+ LOG(ERROR) << "Error in recvmmsg.";
+ return;
}
for (int i = 0; i < res; i++) {
@@ -119,10 +119,10 @@ void UdpTunnelListener::readHandler(std::error_code ec) {
doRecvPacket();
} else if (ec.value() == static_cast<int>(std::errc::operation_canceled)) {
- TRANSPORT_LOGE("The connection has been closed by the application.");
+ LOG(ERROR) << "The connection has been closed by the application.";
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
}
}
#endif
@@ -165,10 +165,10 @@ void UdpTunnelListener::doRecvPacket() {
doRecvPacket();
} else if (ec.value() ==
static_cast<int>(std::errc::operation_canceled)) {
- TRANSPORT_LOGE("The connection has been closed by the application.");
+ LOG(ERROR) << "The connection has been closed by the application.";
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
}
});
#endif
diff --git a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h b/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h
index 0ee40a400..5d197dcb0 100644
--- a/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h
+++ b/libtransport/src/io_modules/forwarder/udp_tunnel_listener.h
@@ -4,11 +4,10 @@
#pragma once
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/portability/platform.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <unordered_map>
namespace std {
diff --git a/libtransport/src/io_modules/loopback/CMakeLists.txt b/libtransport/src/io_modules/loopback/CMakeLists.txt
index ac6dc8068..b5ae0b7f7 100644
--- a/libtransport/src/io_modules/loopback/CMakeLists.txt
+++ b/libtransport/src/io_modules/loopback/CMakeLists.txt
@@ -11,9 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
-
list(APPEND MODULE_HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/loopback_module.h
)
@@ -26,9 +23,8 @@ build_module(loopback_module
SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- # LIBRARY_ROOT_DIR "vpp_plugins"
DEFINITIONS ${COMPILER_DEFINITIONS}
COMPILE_OPTIONS ${COMPILE_FLAGS}
)
diff --git a/libtransport/src/io_modules/loopback/local_face.cc b/libtransport/src/io_modules/loopback/local_face.cc
index a59dab235..b73444330 100644
--- a/libtransport/src/io_modules/loopback/local_face.cc
+++ b/libtransport/src/io_modules/loopback/local_face.cc
@@ -13,13 +13,12 @@
* limitations under the License.
*/
+#include <glog/logging.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
-#include <hicn/transport/utils/log.h>
#include <io_modules/loopback/local_face.h>
-#include <asio/io_service.hpp>
-
namespace transport {
namespace core {
@@ -56,7 +55,7 @@ Face &Face::operator=(Face &&other) {
}
void Face::onPacket(const Packet &packet) {
- TRANSPORT_LOGD("Sending content to local socket.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending content to local socket.";
if (Packet::isInterest(packet.data())) {
rescheduleOnIoService<Interest>(packet);
diff --git a/libtransport/src/io_modules/loopback/local_face.h b/libtransport/src/io_modules/loopback/local_face.h
index 1cbcc2c72..1f4101447 100644
--- a/libtransport/src/io_modules/loopback/local_face.h
+++ b/libtransport/src/io_modules/loopback/local_face.h
@@ -15,12 +15,11 @@
#pragma once
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/core/global_object_pool.h>
#include <hicn/transport/utils/move_wrapper.h>
-#include <asio/io_service.hpp>
-
namespace transport {
namespace core {
diff --git a/libtransport/src/io_modules/loopback/loopback_module.cc b/libtransport/src/io_modules/loopback/loopback_module.cc
index 0bdbf8c8e..f7dd5e7b0 100644
--- a/libtransport/src/io_modules/loopback/loopback_module.cc
+++ b/libtransport/src/io_modules/loopback/loopback_module.cc
@@ -13,8 +13,8 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/errors/not_implemented_exception.h>
-#include <hicn/transport/utils/log.h>
#include <io_modules/loopback/loopback_module.h>
namespace transport {
@@ -35,8 +35,8 @@ bool LoopbackModule::isConnected() { return true; }
void LoopbackModule::send(Packet &packet) {
IoModule::send(packet);
- TRANSPORT_LOGD("LoopbackModule: sending from %u to %d", local_id_,
- 1 - local_id_);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "LoopbackModule: sending from " << local_id_
+ << " to " << 1 - local_id_;
local_faces_.at(1 - local_id_)->send(packet);
}
diff --git a/libtransport/src/io_modules/memif/CMakeLists.txt b/libtransport/src/io_modules/memif/CMakeLists.txt
index c8a930e7b..fc1c1f135 100644
--- a/libtransport/src/io_modules/memif/CMakeLists.txt
+++ b/libtransport/src/io_modules/memif/CMakeLists.txt
@@ -11,8 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
find_package(Vpp REQUIRED)
find_package(Libmemif REQUIRED)
@@ -43,7 +41,7 @@ build_module(memif_module
SHARED
SOURCES ${MODULE_SOURCE_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}-io-modules
LINK_LIBRARIES ${LIBMEMIF_LIBRARIES} ${SAFE_VAPI_LIBRARIES}
INCLUDE_DIRS
${LIBTRANSPORT_INCLUDE_DIRS}
diff --git a/libtransport/src/io_modules/memif/hicn_vapi.c b/libtransport/src/io_modules/memif/hicn_vapi.c
index b83a36b47..6d78026ab 100644
--- a/libtransport/src/io_modules/memif/hicn_vapi.c
+++ b/libtransport/src/io_modules/memif/hicn_vapi.c
@@ -14,7 +14,6 @@
*/
#include <hicn/transport/config.h>
-#include <hicn/transport/utils/log.h>
#include <io_modules/memif/hicn_vapi.h>
#define HICN_VPP_PLUGIN
diff --git a/libtransport/src/io_modules/memif/memif_connector.cc b/libtransport/src/io_modules/memif/memif_connector.cc
index 4a688d68f..68ad52b63 100644
--- a/libtransport/src/io_modules/memif/memif_connector.cc
+++ b/libtransport/src/io_modules/memif/memif_connector.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/errors/not_implemented_exception.h>
#include <io_modules/memif/memif_connector.h>
#include <sys/epoll.h>
@@ -66,6 +67,7 @@ MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback,
disconnect_timer_(
std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
io_service_(io_service),
+ work_(asio::make_work_guard(io_service_)),
memif_connection_(std::make_unique<memif_connection_t>()),
tx_buf_counter_(0),
is_reconnection_(false),
@@ -83,7 +85,7 @@ void MemifConnector::init() {
nullptr, nullptr, nullptr);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_init: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_init: " << memif_strerror(err);
}
}
@@ -95,8 +97,6 @@ void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
createMemif(memif_id, memif_mode, nullptr);
- work_ = std::make_unique<asio::io_service::work>(io_service_);
-
while (state_ != State::CONNECTED) {
MemifConnector::main_event_reactor_.runOneEvent();
}
@@ -107,7 +107,7 @@ void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
int fd = -1;
err = memif_get_queue_efd(memif_connection_->conn, 0, &fd);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_get_queue_efd: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_get_queue_efd: " << memif_strerror(err);
return;
}
@@ -198,11 +198,11 @@ int MemifConnector::deleteMemif() {
err = memif_delete(&c->conn);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_delete: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_delete: " << memif_strerror(err);
}
if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) {
- TRANSPORT_LOGE("memif delete fail");
+ LOG(ERROR) << "memif delete fail";
}
return 0;
@@ -248,8 +248,8 @@ int MemifConnector::controlFdUpdate(int fd, uint8_t events, void *private_ctx) {
memif_err = memif_control_fd_handler(evt.data.fd, event);
if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_control_fd_handler: %s",
- memif_strerror(memif_err));
+ LOG(ERROR) << "memif_control_fd_handler: "
+ << memif_strerror(memif_err);
}
return 0;
@@ -265,7 +265,7 @@ int MemifConnector::bufferAlloc(long n, uint16_t qid) {
err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_buffer_alloc: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_buffer_alloc: " << memif_strerror(err);
return -1;
}
@@ -282,13 +282,13 @@ int MemifConnector::txBurst(uint16_t qid) {
err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_tx_burst: " << memif_strerror(err);
}
// err = memif_refill_queue(c->conn, qid, r, 0);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_tx_burst: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_tx_burst: " << memif_strerror(err);
c->tx_buf_num -= r;
return -1;
}
@@ -350,14 +350,14 @@ int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS &&
err != MEMIF_ERR_NOBUF)) {
- TRANSPORT_LOGE("memif_rx_burst: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_rx_burst: " << memif_strerror(err);
goto error;
}
c->rx_buf_num += rx;
if (TRANSPORT_EXPECT_FALSE(connector->io_service_.stopped())) {
- TRANSPORT_LOGE("socket stopped: ignoring %u packets", rx);
+ LOG(ERROR) << "socket stopped: ignoring " << rx << " packets";
goto error;
}
@@ -369,7 +369,7 @@ int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
auto packet = connector->getPacketFromBuffer(buffer.first, packet_length);
if (!connector->input_buffer_.push(std::move(packet))) {
- TRANSPORT_LOGE("Error pushing packet. Ring buffer full.");
+ LOG(ERROR) << "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
@@ -383,7 +383,7 @@ int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
err = memif_refill_queue(conn, qid, rx, 0);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
}
c->rx_buf_num -= rx;
@@ -400,7 +400,7 @@ error:
err = memif_refill_queue(c->conn, qid, rx, 0);
if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
- TRANSPORT_LOGE("memif_buffer_free: %s", memif_strerror(err));
+ LOG(ERROR) << "memif_buffer_free: " << memif_strerror(err);
}
c->rx_buf_num -= rx;
@@ -413,7 +413,6 @@ void MemifConnector::close() {
disconnect_timer_->asyncWait([this](const std::error_code &ec) {
deleteMemif();
event_reactor_.stop();
- work_.reset();
});
if (memif_worker_ && memif_worker_->joinable()) {
@@ -452,7 +451,7 @@ int MemifConnector::doSend() {
n = bufferAlloc(max, memif_connection_->tx_qid);
if (TRANSPORT_EXPECT_FALSE(n < 0)) {
- TRANSPORT_LOGE("Error allocating buffers.");
+ LOG(ERROR) << "Error allocating buffers.";
return -1;
}
diff --git a/libtransport/src/io_modules/memif/memif_connector.h b/libtransport/src/io_modules/memif/memif_connector.h
index bed3516dc..0a189f893 100644
--- a/libtransport/src/io_modules/memif/memif_connector.h
+++ b/libtransport/src/io_modules/memif/memif_connector.h
@@ -20,10 +20,10 @@
#include <hicn/transport/portability/portability.h>
#include <hicn/transport/utils/ring_buffer.h>
//#include <hicn/transport/core/hicn_vapi.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <utils/epoll_event_reactor.h>
#include <utils/fd_deadline_timer.h>
-#include <asio.hpp>
#include <deque>
#include <mutex>
#include <thread>
@@ -108,7 +108,7 @@ class MemifConnector : public Connector {
std::unique_ptr<utils::FdDeadlineTimer> send_timer_;
std::unique_ptr<utils::FdDeadlineTimer> disconnect_timer_;
asio::io_service &io_service_;
- std::unique_ptr<asio::io_service::work> work_;
+ asio::executor_work_guard<asio::io_context::executor_type> work_;
std::unique_ptr<memif_connection_t> memif_connection_;
uint16_t tx_buf_counter_;
diff --git a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
index dcbcd7ed0..44c8376df 100644
--- a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
+++ b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/config.h>
#include <hicn/transport/errors/not_implemented_exception.h>
#include <io_modules/memif/hicn_vapi.h>
@@ -148,21 +149,19 @@ void VPPForwarderModule::producerConnection() {
void VPPForwarderModule::connect(bool is_consumer) {
int retry = 20;
- TRANSPORT_LOGI("Connecting to VPP through vapi.");
+ LOG(INFO) << "Connecting to VPP through vapi.";
vapi_error_e ret = vapi_connect_safe(&sock_, 0);
while (ret != VAPI_OK && retry > 0) {
- TRANSPORT_LOGE("Error connecting to VPP through vapi. Retrying..");
+ LOG(ERROR) << "Error connecting to VPP through vapi. Retrying..";
--retry;
ret = vapi_connect_safe(&sock_, 0);
}
- if (ret != VAPI_OK) {
- throw std::runtime_error(
- "Impossible to connect to forwarder. Is VPP running?");
- }
+ CHECK_EQ(ret, VAPI_OK)
+ << "Impossible to connect to forwarder. Is VPP running?";
- TRANSPORT_LOGI("Connected to VPP through vapi.");
+ LOG(INFO) << "Connected to VPP through vapi.";
sw_if_index_ = getMemifConfiguration();
@@ -247,7 +246,7 @@ void VPPForwarderModule::closeConnection() {
int ret =
memif_vapi_delete_memif(VPPForwarderModule::sock_, sw_if_index_);
if (ret < 0) {
- TRANSPORT_LOGE("Error deleting memif with sw idx %u.", sw_if_index_);
+ LOG(ERROR) << "Error deleting memif with sw idx " << sw_if_index_;
}
}
diff --git a/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc b/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc
index 0bfcc2a58..62efdc3a5 100644
--- a/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc
+++ b/libtransport/src/io_modules/raw_socket/raw_socket_connector.cc
@@ -15,7 +15,6 @@
#include <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>
@@ -165,7 +164,7 @@ void RawSocketConnector::doSendPacket() {
doSendPacket();
}
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
}
});
}
@@ -185,7 +184,7 @@ void RawSocketConnector::doRecvPacket() {
receive_callback_(std::move(read_msg_));
}
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
}
doRecvPacket();
});
diff --git a/libtransport/src/io_modules/raw_socket/raw_socket_connector.h b/libtransport/src/io_modules/raw_socket/raw_socket_connector.h
index aba4b1105..06892b3d8 100644
--- a/libtransport/src/io_modules/raw_socket/raw_socket_connector.h
+++ b/libtransport/src/io_modules/raw_socket/raw_socket_connector.h
@@ -17,13 +17,12 @@
#include <core/connector.h>
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/name.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <sys/socket.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <deque>
namespace transport {
diff --git a/libtransport/src/io_modules/udp/CMakeLists.txt b/libtransport/src/io_modules/udp/CMakeLists.txt
index 93518d0a2..b9c19d063 100644
--- a/libtransport/src/io_modules/udp/CMakeLists.txt
+++ b/libtransport/src/io_modules/udp/CMakeLists.txt
@@ -11,9 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-
-
list(APPEND MODULE_HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_module.h
${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.h
@@ -24,23 +21,12 @@ list(APPEND MODULE_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/udp_socket_connector.cc
)
-# add_executable(hicnlight_module MACOSX_BUNDLE ${MODULE_SOURCE_FILES})
-# target_include_directories(hicnlight_module PRIVATE ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS})
-# set_target_properties(hicnlight_module PROPERTIES
-# BUNDLE True
-# MACOSX_BUNDLE_GUI_IDENTIFIER my.domain.style.identifier.hicnlight_module
-# MACOSX_BUNDLE_BUNDLE_NAME hicnlight_module
-# MACOSX_BUNDLE_BUNDLE_VERSION "0.1"
-# MACOSX_BUNDLE_SHORT_VERSION_STRING "0.1"
-# # MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/customtemplate.plist.in
-# )
build_module(hicnlight_module
- SHARED
- SOURCES ${MODULE_SOURCE_FILES}
- DEPENDS ${DEPENDENCIES}
- COMPONENT lib${LIBTRANSPORT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
- # LIBRARY_ROOT_DIR "vpp_plugins"
- DEFINITIONS ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILE_FLAGS}
+ SHARED
+ SOURCES ${MODULE_SOURCE_FILES}
+ DEPENDS ${DEPENDENCIES}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILE_FLAGS}
)
diff --git a/libtransport/src/io_modules/udp/udp_socket_connector.cc b/libtransport/src/io_modules/udp/udp_socket_connector.cc
index 456886a54..1412d8c07 100644
--- a/libtransport/src/io_modules/udp/udp_socket_connector.cc
+++ b/libtransport/src/io_modules/udp/udp_socket_connector.cc
@@ -17,8 +17,8 @@
#include <hicn/transport/portability/win_portability.h>
#endif
+#include <glog/logging.h>
#include <hicn/transport/errors/errors.h>
-#include <hicn/transport/utils/log.h>
#include <hicn/transport/utils/object_pool.h>
#include <io_modules/udp/udp_socket_connector.h>
@@ -117,7 +117,7 @@ void UdpSocketConnector::doWrite() {
// The connection has been closed by the application.
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
tryReconnect();
}
});
@@ -137,7 +137,7 @@ void UdpSocketConnector::doRead() {
// The connection has been closed by the application.
return;
} else {
- TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+ LOG(ERROR) << ec.value() << " " << ec.message();
tryReconnect();
}
});
@@ -145,7 +145,7 @@ void UdpSocketConnector::doRead() {
void UdpSocketConnector::tryReconnect() {
if (state_ == Connector::State::CONNECTED) {
- TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n");
+ LOG(ERROR) << "Connection lost. Trying to reconnect...";
state_ = Connector::State::CONNECTING;
is_reconnection_ = true;
io_service_.post([this]() {
@@ -201,7 +201,7 @@ void UdpSocketConnector::handleDeadline(const std::error_code &ec) {
if (!ec) {
io_service_.post([this]() {
socket_.close();
- TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n");
+ LOG(ERROR) << "Error connecting. Is the forwarder running?";
});
}
}
diff --git a/libtransport/src/io_modules/udp/udp_socket_connector.h b/libtransport/src/io_modules/udp/udp_socket_connector.h
index 8ab08e17a..c483e14aa 100644
--- a/libtransport/src/io_modules/udp/udp_socket_connector.h
+++ b/libtransport/src/io_modules/udp/udp_socket_connector.h
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/connector.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/global_object_pool.h>
@@ -24,8 +25,6 @@
#include <hicn/transport/core/packet.h>
#include <hicn/transport/utils/branch_prediction.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <deque>
namespace transport {
diff --git a/libtransport/src/protocols/CMakeLists.txt b/libtransport/src/protocols/CMakeLists.txt
index eba8d1aab..b763e95e2 100644
--- a/libtransport/src/protocols/CMakeLists.txt
+++ b/libtransport/src/protocols/CMakeLists.txt
@@ -11,12 +11,11 @@
# 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}/indexer.h
- ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.h
- ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer_bytestream.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer_bytestream.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/index_manager_bytestream.h
${CMAKE_CURRENT_SOURCE_DIR}/reassembly.h
${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.h
${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.h
@@ -31,12 +30,14 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/cbr.h
${CMAKE_CURRENT_SOURCE_DIR}/errors.h
${CMAKE_CURRENT_SOURCE_DIR}/data_processing_events.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fec_base.h
)
list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/indexer.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/incremental_indexer_bytestream.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/manifest_incremental_indexer_bytestream.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/index_manager_bytestream.cc
${CMAKE_CURRENT_SOURCE_DIR}/reassembly.cc
${CMAKE_CURRENT_SOURCE_DIR}/datagram_reassembly.cc
${CMAKE_CURRENT_SOURCE_DIR}/byte_stream_reassembly.cc
@@ -67,10 +68,11 @@ set(TRANSPORT_CONFIG
install(
FILES ${TRANSPORT_CONFIG}
DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/hicn
- COMPONENT lib${LIBTRANSPORT}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
)
add_subdirectory(rtc)
+add_subdirectory(fec)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/protocols/byte_stream_reassembly.cc b/libtransport/src/protocols/byte_stream_reassembly.cc
index d2bc961c4..ac36d4e61 100644
--- a/libtransport/src/protocols/byte_stream_reassembly.cc
+++ b/libtransport/src/protocols/byte_stream_reassembly.cc
@@ -33,7 +33,7 @@ ByteStreamReassembly::ByteStreamReassembly(
implementation::ConsumerSocket *icn_socket,
TransportProtocol *transport_protocol)
: Reassembly(icn_socket, transport_protocol),
- index_(IndexManager::invalid_index),
+ index_(Indexer::invalid_index),
download_complete_(false) {}
void ByteStreamReassembly::reassemble(
@@ -54,10 +54,14 @@ void ByteStreamReassembly::reassemble(ContentObject &content_object) {
}
}
+void ByteStreamReassembly::reassemble(utils::MemBuf &buffer, uint32_t suffix) {
+ throw errors::NotImplementedException();
+}
+
void ByteStreamReassembly::assembleContent() {
- if (TRANSPORT_EXPECT_FALSE(index_ == IndexManager::invalid_index)) {
- index_ = index_manager_->getNextReassemblySegment();
- if (index_ == IndexManager::invalid_index) {
+ if (TRANSPORT_EXPECT_FALSE(index_ == Indexer::invalid_index)) {
+ index_ = indexer_verifier_->getNextReassemblySegment();
+ if (index_ == Indexer::invalid_index) {
return;
}
}
@@ -72,11 +76,11 @@ void ByteStreamReassembly::assembleContent() {
}
received_packets_.erase(it);
- index_ = index_manager_->getNextReassemblySegment();
+ index_ = indexer_verifier_->getNextReassemblySegment();
it = received_packets_.find((const unsigned int)index_);
}
- if (!download_complete_ && index_ != IndexManager::invalid_index) {
+ if (!download_complete_ && index_ != Indexer::invalid_index) {
transport_protocol_->onReassemblyFailed(index_);
}
}
@@ -108,8 +112,8 @@ bool ByteStreamReassembly::copyContent(ContentObject &content_object) {
current = current->next();
} while (current != &content_object);
- download_complete_ =
- index_manager_->getFinalSuffix() == content_object.getName().getSuffix();
+ download_complete_ = indexer_verifier_->getFinalSuffix() ==
+ content_object.getName().getSuffix();
if (TRANSPORT_EXPECT_FALSE(download_complete_)) {
ret = download_complete_;
@@ -122,17 +126,19 @@ bool ByteStreamReassembly::copyContent(ContentObject &content_object) {
}
void ByteStreamReassembly::reInitialize() {
- index_ = IndexManager::invalid_index;
+ index_ = Indexer::invalid_index;
download_complete_ = false;
received_packets_.clear();
// reset read buffer
ReadCallback *read_callback;
- reassembly_consumer_socket_->getSocketOption(
- interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback);
- read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize());
+ if (reassembly_consumer_socket_) {
+ reassembly_consumer_socket_->getSocketOption(
+ interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback);
+ read_buffer_ = utils::MemBuf::create(read_callback->maxBufferSize());
+ }
}
} // namespace protocol
diff --git a/libtransport/src/protocols/byte_stream_reassembly.h b/libtransport/src/protocols/byte_stream_reassembly.h
index c682d58cb..278740bd3 100644
--- a/libtransport/src/protocols/byte_stream_reassembly.h
+++ b/libtransport/src/protocols/byte_stream_reassembly.h
@@ -27,11 +27,13 @@ class ByteStreamReassembly : public Reassembly {
TransportProtocol *transport_protocol);
protected:
- virtual void reassemble(core::ContentObject &content_object) override;
+ void reassemble(core::ContentObject &content_object) override;
- virtual void reassemble(
+ void reassemble(
std::unique_ptr<core::ContentObjectManifest> &&manifest) override;
+ void reassemble(utils::MemBuf &buffer, uint32_t suffix) override;
+
bool copyContent(core::ContentObject &content_object);
virtual void reInitialize() override;
@@ -40,10 +42,6 @@ class ByteStreamReassembly : public Reassembly {
void assembleContent();
protected:
- // The consumer socket
- // std::unique_ptr<IncrementalIndexManager> incremental_index_manager_;
- // std::unique_ptr<ManifestIndexManager> manifest_index_manager_;
- // IndexVerificationManager *index_manager_;
std::unordered_map<std::uint32_t, core::ContentObject::Ptr> received_packets_;
uint32_t index_;
bool download_complete_;
diff --git a/libtransport/src/protocols/cbr.cc b/libtransport/src/protocols/cbr.cc
index 0bffd7d18..1548cc68d 100644
--- a/libtransport/src/protocols/cbr.cc
+++ b/libtransport/src/protocols/cbr.cc
@@ -26,8 +26,6 @@ CbrTransportProtocol::CbrTransportProtocol(
implementation::ConsumerSocket *icnet_socket)
: RaaqmTransportProtocol(icnet_socket) {}
-int CbrTransportProtocol::start() { return RaaqmTransportProtocol::start(); }
-
void CbrTransportProtocol::reset() {
RaaqmTransportProtocol::reset();
socket_->getSocketOption(GeneralTransportOptions::CURRENT_WINDOW_SIZE,
diff --git a/libtransport/src/protocols/cbr.h b/libtransport/src/protocols/cbr.h
index 20129f6a3..41cdbc98c 100644
--- a/libtransport/src/protocols/cbr.h
+++ b/libtransport/src/protocols/cbr.h
@@ -25,7 +25,8 @@ class CbrTransportProtocol : public RaaqmTransportProtocol {
public:
CbrTransportProtocol(implementation::ConsumerSocket *icnet_socket);
- int start() override;
+ using RaaqmTransportProtocol::start;
+ using RaaqmTransportProtocol::stop;
void reset() override;
diff --git a/libtransport/src/protocols/data_processing_events.h b/libtransport/src/protocols/data_processing_events.h
index 5c8c16157..28732502b 100644
--- a/libtransport/src/protocols/data_processing_events.h
+++ b/libtransport/src/protocols/data_processing_events.h
@@ -24,7 +24,8 @@ namespace protocol {
class ContentObjectProcessingEventCallback {
public:
virtual ~ContentObjectProcessingEventCallback() = default;
- virtual void onPacketDropped(core::Interest &i, core::ContentObject &c) = 0;
+ virtual void onPacketDropped(core::Interest &i, core::ContentObject &c,
+ const std::error_code &reason) = 0;
virtual void onReassemblyFailed(std::uint32_t missing_segment) = 0;
};
diff --git a/libtransport/src/protocols/datagram_reassembly.cc b/libtransport/src/protocols/datagram_reassembly.cc
index 962c1e020..069873a52 100644
--- a/libtransport/src/protocols/datagram_reassembly.cc
+++ b/libtransport/src/protocols/datagram_reassembly.cc
@@ -14,6 +14,7 @@
*/
#include <protocols/datagram_reassembly.h>
+#include <protocols/transport_protocol.h>
namespace transport {
@@ -25,7 +26,17 @@ DatagramReassembly::DatagramReassembly(
: Reassembly(icn_socket, transport_protocol) {}
void DatagramReassembly::reassemble(core::ContentObject& content_object) {
- read_buffer_ = content_object.getPayload();
+ auto read_buffer = content_object.getPayload();
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Size of payload: " << read_buffer->length() << ". Trimming "
+ << transport_protocol_->transportHeaderLength();
+ read_buffer->trimStart(transport_protocol_->transportHeaderLength());
+ Reassembly::read_buffer_ = std::move(read_buffer);
+ Reassembly::notifyApplication();
+}
+
+void DatagramReassembly::reassemble(utils::MemBuf& buffer, uint32_t suffix) {
+ read_buffer_ = buffer.cloneOne();
Reassembly::notifyApplication();
}
diff --git a/libtransport/src/protocols/datagram_reassembly.h b/libtransport/src/protocols/datagram_reassembly.h
index 3462212d3..de294df06 100644
--- a/libtransport/src/protocols/datagram_reassembly.h
+++ b/libtransport/src/protocols/datagram_reassembly.h
@@ -27,11 +27,13 @@ class DatagramReassembly : public Reassembly {
TransportProtocol *transport_protocol);
virtual void reassemble(core::ContentObject &content_object) override;
+ void reassemble(utils::MemBuf &buffer, uint32_t suffix) override;
virtual void reInitialize() override;
virtual void reassemble(
std::unique_ptr<core::ContentObjectManifest> &&manifest) override {
return;
}
+ bool reassembleUnverified() override { return true; }
};
} // namespace protocol
diff --git a/libtransport/src/protocols/errors.cc b/libtransport/src/protocols/errors.cc
index ae7b6e634..183fcc574 100644
--- a/libtransport/src/protocols/errors.cc
+++ b/libtransport/src/protocols/errors.cc
@@ -39,6 +39,9 @@ std::string protocol_category_impl::message(int ev) const {
case protocol_error::integrity_verification_failed: {
return "Integrity verification failed";
}
+ case protocol_error::verification_failed: {
+ return "Verification failed";
+ }
case protocol_error::no_verifier_provided: {
return "Transport cannot get any verifier for the given data.";
}
@@ -52,6 +55,12 @@ std::string protocol_category_impl::message(int ev) const {
case protocol_error::session_aborted: {
return "The session has been aborted by the application.";
}
+ case protocol_error::not_reassemblable: {
+ return "The session has been aborted by the application.";
+ }
+ case protocol_error::duplicated_content: {
+ return "The session has been aborted by the application.";
+ }
default: {
return "Unknown protocol error";
}
@@ -59,4 +68,4 @@ std::string protocol_category_impl::message(int ev) const {
}
} // namespace protocol
-} // namespace transport \ No newline at end of file
+} // namespace transport
diff --git a/libtransport/src/protocols/errors.h b/libtransport/src/protocols/errors.h
index cb3d3474e..58dadae5a 100644
--- a/libtransport/src/protocols/errors.h
+++ b/libtransport/src/protocols/errors.h
@@ -37,10 +37,14 @@ enum class protocol_error {
success = 0,
signature_verification_failed,
integrity_verification_failed,
+ verification_failed,
no_verifier_provided,
io_error,
max_retransmissions_error,
session_aborted,
+ not_reassemblable,
+ delayed_reassemble,
+ duplicated_content
};
/**
diff --git a/libtransport/src/security/CMakeLists.txt b/libtransport/src/protocols/fec/CMakeLists.txt
index 0e7b5832b..6d61ae043 100644
--- a/libtransport/src/security/CMakeLists.txt
+++ b/libtransport/src/protocols/fec/CMakeLists.txt
@@ -11,12 +11,26 @@
# 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}/fec.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rs.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fec_info.h
+)
list(APPEND SOURCE_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/fec.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rs.cc
)
+if (ENABLE_RELY)
+ list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/rely.h
+ )
+
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/rely.cc
+ )
+endif()
+
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/protocols/fec/fec.cc b/libtransport/src/protocols/fec/fec.cc
new file mode 100644
index 000000000..16a04cb98
--- /dev/null
+++ b/libtransport/src/protocols/fec/fec.cc
@@ -0,0 +1,838 @@
+/*
+ * fec.c -- forward error correction based on Vandermonde matrices
+ * 980624
+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
+ *
+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * The following parameter defines how many bits are used for
+ * field elements. The code supports any value from 2 to 16
+ * but fastest operation is achieved with 8 bit elements
+ * This is the only parameter you may want to change.
+ */
+#ifndef GF_BITS
+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
+#endif
+
+#include "fec.h"
+
+#include <hicn/transport/portability/platform.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * XXX This disable a warning raising only in some platforms.
+ * TODO Check if this warning is a mistake or it is a real bug:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83404
+ * https://gcc.gnu.org/bugzilla//show_bug.cgi?id=88059
+ */
+#ifndef __clang__
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
+
+/*
+ * compatibility stuff
+ */
+#ifdef MSDOS /* but also for others, e.g. sun... */
+#define NEED_BCOPY
+#define bcmp(a, b, n) memcmp(a, b, n)
+#endif
+
+#ifdef ANDROID
+#define bcmp(a, b, n) memcmp(a, b, n)
+#endif
+
+#ifdef NEED_BCOPY
+#define bcopy(s, d, siz) memcpy((d), (s), (siz))
+#define bzero(d, siz) memset((d), '\0', (siz))
+#endif
+
+/*
+ * stuff used for testing purposes only
+ */
+
+#ifdef TEST
+#define DEB(x)
+#define DDB(x) x
+#define DEBUG 0 /* minimal debugging */
+#ifdef MSDOS
+#include <time.h>
+struct timeval {
+ unsigned long ticks;
+};
+#define gettimeofday(x, dummy) \
+ { (x)->ticks = clock(); }
+#define DIFF_T(a, b) (1 + 1000000 * (a.ticks - b.ticks) / CLOCKS_PER_SEC)
+typedef unsigned long u_long;
+typedef unsigned short u_short;
+#else /* typically, unix systems */
+#include <sys/time.h>
+#define DIFF_T(a, b) \
+ (1 + 1000000 * (a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec))
+#endif
+
+#define TICK(t) \
+ { \
+ struct timeval x; \
+ gettimeofday(&x, NULL); \
+ t = x.tv_usec + 1000000 * (x.tv_sec & 0xff); \
+ }
+#define TOCK(t) \
+ { \
+ u_long t1; \
+ TICK(t1); \
+ if (t1 < t) \
+ t = 256000000 + t1 - t; \
+ else \
+ t = t1 - t; \
+ if (t == 0) t = 1; \
+ }
+
+u_long ticks[10]; /* vars for timekeeping */
+#else
+#define DEB(x)
+#define DDB(x)
+#define TICK(x)
+#define TOCK(x)
+#endif /* TEST */
+
+/*
+ * You should not need to change anything beyond this point.
+ * The first part of the file implements linear algebra in GF.
+ *
+ * gf is the type used to store an element of the Galois Field.
+ * Must constain at least GF_BITS bits.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium. We use int whenever have to deal with an
+ * index, since they are generally faster.
+ */
+#if (GF_BITS < 2 && GF_BITS > 16)
+#error "GF_BITS must be 2 .. 16"
+#endif
+
+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
+
+/*
+ * Primitive polynomials - see Lin & Costello, Appendix A,
+ * and Lee & Messerschmitt, p. 453.
+ */
+static const char *allPp[] = {
+ /* GF_BITS polynomial */
+ NULL, /* 0 no code */
+ NULL, /* 1 no code */
+ "111", /* 2 1+x+x^2 */
+ "1101", /* 3 1+x+x^3 */
+ "11001", /* 4 1+x+x^4 */
+ "101001", /* 5 1+x^2+x^5 */
+ "1100001", /* 6 1+x+x^6 */
+ "10010001", /* 7 1 + x^3 + x^7 */
+ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */
+ "1000100001", /* 9 1+x^4+x^9 */
+ "10010000001", /* 10 1+x^3+x^10 */
+ "101000000001", /* 11 1+x^2+x^11 */
+ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */
+ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */
+ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */
+ "1100000000000001", /* 15 1+x+x^15 */
+ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
+};
+
+/*
+ * To speed up computations, we have tables for logarithm, exponent
+ * and inverse of a number. If GF_BITS <= 8, we use a table for
+ * multiplication as well (it takes 64K, no big deal even on a PDA,
+ * especially because it can be pre-initialized an put into a ROM!),
+ * otherwhise we use a table of logarithms.
+ * In any case the macro gf_mul(x,y) takes care of multiplications.
+ */
+
+static gf gf_exp[2 * GF_SIZE]; /* index->poly form conversion table */
+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
+static gf inverse[GF_SIZE + 1]; /* inverse of field elem. */
+ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
+
+/*
+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
+ * without a slow divide.
+ */
+static inline gf modnn(int x) {
+ while (x >= GF_SIZE) {
+ x -= GF_SIZE;
+ x = (x >> GF_BITS) + (x & GF_SIZE);
+ }
+ return x;
+}
+
+#define SWAP(a, b, t) \
+ { \
+ t tmp; \
+ tmp = a; \
+ a = b; \
+ b = tmp; \
+ }
+
+/*
+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
+ * faster to use a multiplication table.
+ *
+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
+ * many numbers by the same constant. In this case the first
+ * call sets the constant, and others perform the multiplications.
+ * A value related to the multiplication is held in a local variable
+ * declared with USE_GF_MULC . See usage in addmul1().
+ */
+#if (GF_BITS <= 8)
+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
+
+#define gf_mul(x, y) gf_mul_table[x][y]
+
+#define USE_GF_MULC gf *__gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
+
+static void init_mul_table() {
+ int i, j;
+ for (i = 0; i < GF_SIZE + 1; i++)
+ for (j = 0; j < GF_SIZE + 1; j++)
+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j])];
+
+ for (j = 0; j < GF_SIZE + 1; j++) gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
+}
+#else /* GF_BITS > 8 */
+static inline gf gf_mul(x, y) {
+ if ((x) == 0 || (y) == 0) return 0;
+
+ return gf_exp[gf_log[x] + gf_log[y]];
+}
+#define init_mul_table()
+
+#define USE_GF_MULC register gf *__gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[gf_log[c]]
+#define GF_ADDMULC(dst, x) \
+ { \
+ if (x) dst ^= __gf_mulc_[gf_log[x]]; \
+ }
+#endif
+
+/*
+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
+ * Lookup tables:
+ * index->polynomial form gf_exp[] contains j= \alpha^i;
+ * polynomial form -> index form gf_log[ j = \alpha^i ] = i
+ * \alpha=x is the primitive element of GF(2^m)
+ *
+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
+ * multiplication of two numbers can be resolved without calling modnn
+ */
+
+/*
+ * i use malloc so many times, it is easier to put checks all in
+ * one place.
+ */
+static void *my_malloc(int sz, const char *err_string) {
+ void *p = malloc(sz);
+ if (p == NULL) {
+ fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
+ exit(1);
+ }
+ return p;
+}
+
+#define NEW_GF_MATRIX(rows, cols) \
+ (gf *)my_malloc(rows *cols * sizeof(gf), " ## __LINE__ ## ")
+
+/*
+ * initialize the data structures used for computations in GF.
+ */
+static void generate_gf(void) {
+ int i;
+ gf mask;
+ const char *Pp = allPp[GF_BITS];
+
+ mask = 1; /* x ** 0 = 1 */
+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
+ /*
+ * first, generate the (polynomial representation of) powers of \alpha,
+ * which are stored in gf_exp[i] = \alpha ** i .
+ * At the same time build gf_log[gf_exp[i]] = i .
+ * The first GF_BITS powers are simply bits shifted to the left.
+ */
+ for (i = 0; i < GF_BITS; i++, mask <<= 1) {
+ gf_exp[i] = mask;
+ gf_log[gf_exp[i]] = i;
+ /*
+ * If Pp[i] == 1 then \alpha ** i occurs in poly-repr
+ * gf_exp[GF_BITS] = \alpha ** GF_BITS
+ */
+ if (Pp[i] == '1') gf_exp[GF_BITS] ^= mask;
+ }
+ /*
+ * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
+ * compute its inverse.
+ */
+ gf_log[gf_exp[GF_BITS]] = GF_BITS;
+ /*
+ * Poly-repr of \alpha ** (i+1) is given by poly-repr of
+ * \alpha ** i shifted left one-bit and accounting for any
+ * \alpha ** GF_BITS term that may occur when poly-repr of
+ * \alpha ** i is shifted.
+ */
+ mask = 1 << (GF_BITS - 1);
+ for (i = GF_BITS + 1; i < GF_SIZE; i++) {
+ if (gf_exp[i - 1] >= mask)
+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
+ else
+ gf_exp[i] = gf_exp[i - 1] << 1;
+ gf_log[gf_exp[i]] = i;
+ }
+ /*
+ * log(0) is not defined, so use a special value
+ */
+ gf_log[0] = GF_SIZE;
+ /* set the extended gf_exp values for fast multiply */
+ for (i = 0; i < GF_SIZE; i++) gf_exp[i + GF_SIZE] = gf_exp[i];
+
+ /*
+ * again special cases. 0 has no inverse. This used to
+ * be initialized to GF_SIZE, but it should make no difference
+ * since noone is supposed to read from here.
+ */
+ inverse[0] = 0;
+ inverse[1] = 1;
+ for (i = 2; i <= GF_SIZE; i++) inverse[i] = gf_exp[GF_SIZE - gf_log[i]];
+}
+
+/*
+ * Various linear algebra operations that i use often.
+ */
+
+/*
+ * addmul() computes dst[] = dst[] + c * src[]
+ * This is used often, so better optimize it! Currently the loop is
+ * unrolled 16 times, a good value for 486 and pentium-class machines.
+ * The case c=0 is also optimized, whereas c=1 is not. These
+ * calls are unfrequent in my typical apps so I did not bother.
+ *
+ * Note that gcc on
+ */
+#define addmul(dst, src, c, sz) \
+ if (c != 0) addmul1(dst, src, c, sz)
+
+#define UNROLL 16 /* 1, 4, 8, 16 */
+static void addmul1(gf *dst1, gf *src1, gf c, int sz) {
+ USE_GF_MULC;
+ gf *dst = dst1, *src = src1;
+ gf *lim = &dst[sz - UNROLL + 1];
+
+ GF_MULC0(c);
+
+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
+ for (; dst < lim; dst += UNROLL, src += UNROLL) {
+ GF_ADDMULC(dst[0], src[0]);
+ GF_ADDMULC(dst[1], src[1]);
+ GF_ADDMULC(dst[2], src[2]);
+ GF_ADDMULC(dst[3], src[3]);
+#if (UNROLL > 4)
+ GF_ADDMULC(dst[4], src[4]);
+ GF_ADDMULC(dst[5], src[5]);
+ GF_ADDMULC(dst[6], src[6]);
+ GF_ADDMULC(dst[7], src[7]);
+#endif
+#if (UNROLL > 8)
+ GF_ADDMULC(dst[8], src[8]);
+ GF_ADDMULC(dst[9], src[9]);
+ GF_ADDMULC(dst[10], src[10]);
+ GF_ADDMULC(dst[11], src[11]);
+ GF_ADDMULC(dst[12], src[12]);
+ GF_ADDMULC(dst[13], src[13]);
+ GF_ADDMULC(dst[14], src[14]);
+ GF_ADDMULC(dst[15], src[15]);
+#endif
+ }
+#endif
+ lim += UNROLL - 1;
+ for (; dst < lim; dst++, src++) /* final components */
+ GF_ADDMULC(*dst, *src);
+}
+
+/*
+ * computes C = AB where A is n*k, B is k*m, C is n*m
+ */
+static void matmul(gf *a, gf *b, gf *c, int n, int k, int m) {
+ int row, col, i;
+
+ for (row = 0; row < n; row++) {
+ for (col = 0; col < m; col++) {
+ gf *pa = &a[row * k];
+ gf *pb = &b[col];
+ gf acc = 0;
+ for (i = 0; i < k; i++, pa++, pb += m) acc ^= gf_mul(*pa, *pb);
+ c[row * m + col] = acc;
+ }
+ }
+}
+
+#ifdef DEBUGG
+/*
+ * returns 1 if the square matrix is identiy
+ * (only for test)
+ */
+static int is_identity(gf *m, int k) {
+ int row, col;
+ for (row = 0; row < k; row++)
+ for (col = 0; col < k; col++)
+ if ((row == col && *m != 1) || (row != col && *m != 0))
+ return 0;
+ else
+ m++;
+ return 1;
+}
+#endif /* debug */
+
+/*
+ * invert_mat() takes a matrix and produces its inverse
+ * k is the size of the matrix.
+ * (Gauss-Jordan, adapted from Numerical Recipes in C)
+ * Return non-zero if singular.
+ */
+DEB(int pivloops = 0; int pivswaps = 0; /* diagnostic */)
+static int invert_mat(gf *src, int k) {
+ gf c, *p;
+ int irow, icol, row, col, i, ix;
+
+ int error = 1;
+ int *indxc = (int *)my_malloc(k * sizeof(int), "indxc");
+ int *indxr = (int *)my_malloc(k * sizeof(int), "indxr");
+ int *ipiv = (int *)my_malloc(k * sizeof(int), "ipiv");
+ gf *id_row = NEW_GF_MATRIX(1, k);
+ gf *temp_row = NEW_GF_MATRIX(1, k);
+
+ bzero(id_row, k * sizeof(gf));
+ DEB(pivloops = 0; pivswaps = 0; /* diagnostic */)
+ /*
+ * ipiv marks elements already used as pivots.
+ */
+ for (i = 0; i < k; i++) ipiv[i] = 0;
+
+ for (col = 0; col < k; col++) {
+ gf *pivot_row;
+ /*
+ * Zeroing column 'col', look for a non-zero element.
+ * First try on the diagonal, if it fails, look elsewhere.
+ */
+ irow = icol = -1;
+ if (ipiv[col] != 1 && src[col * k + col] != 0) {
+ irow = col;
+ icol = col;
+ goto found_piv;
+ }
+ for (row = 0; row < k; row++) {
+ if (ipiv[row] != 1) {
+ for (ix = 0; ix < k; ix++) {
+ DEB(pivloops++;)
+ if (ipiv[ix] == 0) {
+ if (src[row * k + ix] != 0) {
+ irow = row;
+ icol = ix;
+ goto found_piv;
+ }
+ } else if (ipiv[ix] > 1) {
+ fprintf(stderr, "singular matrix\n");
+ goto fail;
+ }
+ }
+ }
+ }
+ if (icol == -1) {
+ fprintf(stderr, "XXX pivot not found!\n");
+ goto fail;
+ }
+ found_piv:
+ ++(ipiv[icol]);
+ /*
+ * swap rows irow and icol, so afterwards the diagonal
+ * element will be correct. Rarely done, not worth
+ * optimizing.
+ */
+ if (irow != icol) {
+ for (ix = 0; ix < k; ix++) {
+ SWAP(src[irow * k + ix], src[icol * k + ix], gf);
+ }
+ }
+ indxr[col] = irow;
+ indxc[col] = icol;
+ pivot_row = &src[icol * k];
+ c = pivot_row[icol];
+ if (c == 0) {
+ fprintf(stderr, "singular matrix 2\n");
+ goto fail;
+ }
+ if (c != 1) { /* otherwhise this is a NOP */
+ /*
+ * this is done often , but optimizing is not so
+ * fruitful, at least in the obvious ways (unrolling)
+ */
+ DEB(pivswaps++;)
+ c = inverse[c];
+ pivot_row[icol] = 1;
+ for (ix = 0; ix < k; ix++) pivot_row[ix] = gf_mul(c, pivot_row[ix]);
+ }
+ /*
+ * from all rows, remove multiples of the selected row
+ * to zero the relevant entry (in fact, the entry is not zero
+ * because we know it must be zero).
+ * (Here, if we know that the pivot_row is the identity,
+ * we can optimize the addmul).
+ */
+ id_row[icol] = 1;
+ if (bcmp(pivot_row, id_row, k * sizeof(gf)) != 0) {
+ for (p = src, ix = 0; ix < k; ix++, p += k) {
+ if (ix != icol) {
+ c = p[icol];
+ p[icol] = 0;
+ addmul(p, pivot_row, c, k);
+ }
+ }
+ }
+ id_row[icol] = 0;
+ } /* done all columns */
+ for (col = k - 1; col >= 0; col--) {
+ if (indxr[col] < 0 || indxr[col] >= k)
+ fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
+ else if (indxc[col] < 0 || indxc[col] >= k)
+ fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
+ else if (indxr[col] != indxc[col]) {
+ for (row = 0; row < k; row++) {
+ SWAP(src[row * k + indxr[col]], src[row * k + indxc[col]], gf);
+ }
+ }
+ }
+ error = 0;
+fail:
+ free(indxc);
+ free(indxr);
+ free(ipiv);
+ free(id_row);
+ free(temp_row);
+ return error;
+}
+
+/*
+ * fast code for inverting a vandermonde matrix.
+ * XXX NOTE: It assumes that the matrix
+ * is not singular and _IS_ a vandermonde matrix. Only uses
+ * the second column of the matrix, containing the p_i's.
+ *
+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
+ * largely revised for my purposes.
+ * p = coefficients of the matrix (p_i)
+ * q = values of the polynomial (known)
+ */
+
+int invert_vdm(gf *src, int k) {
+ int i, j, row, col;
+ gf *b, *c, *p;
+ gf t, xx;
+
+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
+ return 0;
+ /*
+ * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
+ * b holds the coefficient for the matrix inversion
+ */
+ c = NEW_GF_MATRIX(1, k);
+ b = NEW_GF_MATRIX(1, k);
+
+ p = NEW_GF_MATRIX(1, k);
+
+ for (j = 1, i = 0; i < k; i++, j += k) {
+ c[i] = 0;
+ p[i] = src[j]; /* p[i] */
+ }
+ /*
+ * construct coeffs. recursively. We know c[k] = 1 (implicit)
+ * and start P_0 = x - p_0, then at each stage multiply by
+ * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
+ * After k steps we are done.
+ */
+ c[k - 1] = p[0]; /* really -p(0), but x = -x in GF(2^m) */
+ for (i = 1; i < k; i++) {
+ gf p_i = p[i]; /* see above comment */
+ for (j = k - 1 - (i - 1); j < k - 1; j++) c[j] ^= gf_mul(p_i, c[j + 1]);
+ c[k - 1] ^= p_i;
+ }
+
+ for (row = 0; row < k; row++) {
+ /*
+ * synthetic division etc.
+ */
+ xx = p[row];
+ t = 1;
+ b[k - 1] = 1; /* this is in fact c[k] */
+ for (i = k - 2; i >= 0; i--) {
+ b[i] = c[i + 1] ^ gf_mul(xx, b[i + 1]);
+ t = gf_mul(xx, t) ^ b[i];
+ }
+ for (col = 0; col < k; col++)
+ src[col * k + row] = gf_mul(inverse[t], b[col]);
+ }
+ free(c);
+ free(b);
+ free(p);
+ return 0;
+}
+
+static int fec_initialized = 0;
+static void init_fec() {
+ TICK(ticks[0]);
+ generate_gf();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
+ TICK(ticks[0]);
+ init_mul_table();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
+ fec_initialized = 1;
+}
+
+/*
+ * This section contains the proper FEC encoding/decoding routines.
+ * The encoding matrix is computed starting with a Vandermonde matrix,
+ * and then transforming it into a systematic matrix.
+ */
+
+#define FEC_MAGIC 0xFECC0DEC
+
+void fec_free(struct fec_parms *p) {
+ if (p == NULL || p->magic != (((FEC_MAGIC ^ p->k) ^ p->n) ^
+ (unsigned long)(p->enc_matrix))) {
+ fprintf(stderr, "bad parameters to fec_free\n");
+ return;
+ }
+ free(p->enc_matrix);
+ free(p);
+}
+
+/*
+ * create a new encoder, returning a descriptor. This contains k,n and
+ * the encoding matrix.
+ */
+struct fec_parms *fec_new(int k, int n) {
+ int row, col;
+ gf *p, *tmp_m;
+
+ struct fec_parms *retval;
+
+ if (fec_initialized == 0) init_fec();
+
+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n) {
+ fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n", k, n, GF_SIZE);
+ return NULL;
+ }
+ retval = (struct fec_parms *)my_malloc(sizeof(struct fec_parms), "new_code");
+ retval->k = k;
+ retval->n = n;
+ retval->enc_matrix = NEW_GF_MATRIX(n, k);
+ retval->magic = ((FEC_MAGIC ^ k) ^ n) ^ (unsigned long)(retval->enc_matrix);
+ tmp_m = NEW_GF_MATRIX(n, k);
+ /*
+ * fill the matrix with powers of field elements, starting from 0.
+ * The first row is special, cannot be computed with exp. table.
+ */
+ tmp_m[0] = 1;
+ for (col = 1; col < k; col++) tmp_m[col] = 0;
+ for (p = tmp_m + k, row = 0; row < n - 1; row++, p += k) {
+ for (col = 0; col < k; col++) p[col] = gf_exp[modnn(row * col)];
+ }
+
+ /*
+ * quick code to build systematic matrix: invert the top
+ * k*k vandermonde matrix, multiply right the bottom n-k rows
+ * by the inverse, and construct the identity matrix at the top.
+ */
+ TICK(ticks[3]);
+ invert_vdm(tmp_m, k); /* much faster than invert_mat */
+ matmul(tmp_m + k * k, tmp_m, retval->enc_matrix + k * k, n - k, k, k);
+ /*
+ * the upper matrix is I so do not bother with a slow multiply
+ */
+ bzero(retval->enc_matrix, k * k * sizeof(gf));
+ for (p = retval->enc_matrix, col = 0; col < k; col++, p += k + 1) *p = 1;
+ free(tmp_m);
+ TOCK(ticks[3]);
+
+ DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", ticks[3]);)
+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
+ return retval;
+}
+
+/*
+ * fec_encode accepts as input pointers to n data packets of size sz,
+ * and produces as output a packet pointed to by fec, computed
+ * with index "index".
+ */
+void fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) {
+ int i, k = code->k;
+ gf *p;
+
+ if (GF_BITS > 8) sz /= 2;
+
+ if (index < k)
+ bcopy(src[index], fec, sz * sizeof(gf));
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index * k]);
+ bzero(fec, sz * sizeof(gf));
+ for (i = 0; i < k; i++) addmul(fec, src[i], p[i], sz);
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n", index, code->n - 1);
+}
+
+/*
+ * shuffle move src packets in their position
+ */
+static int shuffle(gf *pkt[], int index[], int k) {
+ int i;
+
+ for (i = 0; i < k;) {
+ if (index[i] >= k || index[i] == i)
+ i++;
+ else {
+ /*
+ * put pkt in the right position (first check for conflicts).
+ */
+ int c = index[i];
+
+ if (index[c] == c) {
+ DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
+ return 1;
+ }
+ SWAP(index[i], index[c], int);
+ SWAP(pkt[i], pkt[c], gf *);
+ }
+ }
+ DEB(/* just test that it works... */
+ for (i = 0; i < k; i++) {
+ if (index[i] < k && index[i] != i) {
+ fprintf(stderr, "shuffle: after\n");
+ for (i = 0; i < k; i++) fprintf(stderr, "%3d ", index[i]);
+ fprintf(stderr, "\n");
+ return 1;
+ }
+ })
+ return 0;
+}
+
+/*
+ * build_decode_matrix constructs the encoding matrix given the
+ * indexes. The matrix must be already allocated as
+ * a vector of k*k elements, in row-major order
+ */
+static gf *build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[]) {
+ int i, k = code->k;
+ gf *p, *matrix = NEW_GF_MATRIX(k, k);
+
+ TICK(ticks[9]);
+ for (i = 0, p = matrix; i < k; i++, p += k) {
+#if 1 /* this is simply an optimization, not very useful indeed */
+ if (index[i] < k) {
+ bzero(p, k * sizeof(gf));
+ p[i] = 1;
+ } else
+#endif
+ if (index[i] < code->n)
+ bcopy(&(code->enc_matrix[index[i] * k]), p, k * sizeof(gf));
+ else {
+ fprintf(stderr, "decode: invalid index %d (max %d)\n", index[i],
+ code->n - 1);
+ free(matrix);
+ return NULL;
+ }
+ }
+ TICK(ticks[9]);
+ if (invert_mat(matrix, k)) {
+ free(matrix);
+ matrix = NULL;
+ }
+ TOCK(ticks[9]);
+ return matrix;
+}
+
+/*
+ * fec_decode receives as input a vector of packets, the indexes of
+ * packets, and produces the correct vector as output.
+ *
+ * Input:
+ * code: pointer to code descriptor
+ * pkt: pointers to received packets. They are modified
+ * to store the output packets (in place)
+ * index: pointer to packet indexes (modified)
+ * sz: size of each packet
+ */
+int fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) {
+ gf *m_dec;
+ gf **new_pkt;
+ int row, col, k = code->k;
+
+ if (GF_BITS > 8) sz /= 2;
+
+ if (shuffle(pkt, index, k)) /* error if true */
+ return 1;
+ m_dec = build_decode_matrix(code, pkt, index);
+
+ if (m_dec == NULL) return 1; /* error */
+ /*
+ * do the actual decoding
+ */
+ new_pkt = (gf **)my_malloc(k * sizeof(gf *), "new pkt pointers");
+ for (row = 0; row < k; row++) {
+ if (index[row] >= k) {
+ new_pkt[row] = (gf *)my_malloc(sz * sizeof(gf), "new pkt buffer");
+ bzero(new_pkt[row], sz * sizeof(gf));
+ for (col = 0; col < k; col++)
+ addmul(new_pkt[row], pkt[col], m_dec[row * k + col], sz);
+ }
+ }
+ /*
+ * move pkts to their final destination
+ */
+ for (row = 0; row < k; row++) {
+ if (index[row] >= k) {
+ bcopy(new_pkt[row], pkt[row], sz * sizeof(gf));
+ free(new_pkt[row]);
+ }
+ }
+ free(new_pkt);
+ free(m_dec);
+
+ return 0;
+}
diff --git a/libtransport/src/core/fec.h b/libtransport/src/protocols/fec/fec.h
index 8234057a7..7710bb7af 100644
--- a/libtransport/src/core/fec.h
+++ b/libtransport/src/protocols/fec/fec.h
@@ -39,7 +39,7 @@
* This is the only parameter you may want to change.
*/
#ifndef GF_BITS
-#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
#endif
#if (GF_BITS <= 8)
@@ -48,16 +48,16 @@ typedef unsigned char gf;
typedef unsigned short gf;
#endif
-#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
struct fec_parms {
- unsigned long magic ;
- int k, n ; /* parameters of the code */
- gf *enc_matrix ;
+ unsigned long magic;
+ int k, n; /* parameters of the code */
+ gf *enc_matrix;
};
-void fec_free(struct fec_parms *p) ;
-struct fec_parms *fec_new(int k, int n) ;
+void fec_free(struct fec_parms *p);
+struct fec_parms *fec_new(int k, int n);
void fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz);
int fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz);
diff --git a/libtransport/src/protocols/fec/fec_info.h b/libtransport/src/protocols/fec/fec_info.h
new file mode 100644
index 000000000..bdfc4d3af
--- /dev/null
+++ b/libtransport/src/protocols/fec/fec_info.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/not_implemented_exception.h>
+
+namespace transport {
+namespace protocol {
+
+namespace fec {
+
+template <typename T>
+struct FecInfo {
+ static bool isFec() { throw errors::NotImplementedException(); }
+ static uint32_t nextSymbol(uint32_t index) {
+ throw errors::NotImplementedException();
+ }
+ static uint32_t nextSource(uint32_t index) {
+ throw errors::NotImplementedException();
+ }
+};
+
+template <uint32_t K, uint32_t N>
+struct Code {};
+
+template <uint32_t K, uint32_t N>
+struct FecInfo<Code<K, N>> {
+ static bool isFec(uint32_t index) { return (index % N) >= K; }
+
+ static uint32_t nextSymbol(uint32_t index) {
+ if (isFec(index)) {
+ return index;
+ }
+
+ return index + (K - (index % N));
+ }
+
+ static uint32_t nextSource(uint32_t index) {
+ if (!isFec(index)) {
+ return index;
+ }
+
+ return index + (N - (index % N));
+ }
+};
+
+} // namespace fec
+} // namespace protocol
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/fec/rely.cc b/libtransport/src/protocols/fec/rely.cc
new file mode 100644
index 000000000..7a30a62e2
--- /dev/null
+++ b/libtransport/src/protocols/fec/rely.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec/rely.h>
+
+#include <rely/packet.hpp>
+
+namespace transport {
+namespace protocol {
+namespace fec {
+
+RelyEncoder::RelyEncoder(uint32_t k, uint32_t n, uint32_t seq_offset)
+ : RelyBase(k, n) {
+ configure(kmtu, ktimeout, kmax_stream_size);
+ set_repair_trigger(k_, n_ - k_, n_ - k_);
+}
+
+void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
+ uint32_t offset) {
+ // Get pointer to payload, leaving space to insert FEC header.
+ // TODO Check if this additional header is really needed.
+ auto data = content_object.writableData() + offset - sizeof(fec_header);
+ auto length = content_object.length() - offset + sizeof(fec_header);
+
+ // Check packet length does not exceed maximum length supported by the
+ // encoder (otherwise segmentation would take place).
+ assert(length < max_packet_bytes());
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Encoding packet of length " << length - sizeof(fec_header);
+
+ // Get the suffix. With rely we need to write it in the fec_header in order to
+ // be able to recognize the seq number upon recovery.
+ auto suffix = content_object.getName().getSuffix();
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Producing packet " << suffix
+ << " (index == " << current_index_ << ")";
+
+ // Consume payload. Add fec_header in front before feeding payload to encoder,
+ // and copy original content of packet
+ fec_header *h = reinterpret_cast<fec_header *>(data);
+ fec_header copy = *h;
+ h->setSeqNumberBase(suffix);
+ auto packets = consume(data, length, getCurrentTime());
+ assert(packets == 1);
+
+ // Update packet counter
+ current_index_ += packets;
+
+ // Restore original packet content and increment data pointer to the correct
+ // position
+ *h = copy;
+ data += sizeof(fec_header);
+
+ // Check position of this packet inside N size block
+ auto i = current_index_ % n_;
+
+ // encoder will produce a source packet
+ if (i <= k_) {
+ // Rely modifies the payload of the packet. We replace the packet with the
+ // one returned by rely.
+ // TODO Optimize it by copying only the RELY header
+
+ // Be sure encoder can produce
+ assert(can_produce());
+
+ // Check new payload size and make sure it fits in packet buffer
+ auto new_payload_size = produce_bytes();
+ int difference = new_payload_size - length;
+
+ assert(difference > 0);
+ assert(content_object.ensureCapacity(difference));
+
+ // Update length
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "The packet length will be incremented by "
+ << difference + sizeof(fec_header);
+ content_object.append(difference + sizeof(fec_header));
+ content_object.updateLength();
+
+ // Make sure we got a source packet, otherwise we would put a repair symbol
+ // in a source packet
+ assert(rely::packet_is_systematic(produce_data()));
+
+ // Copy rely packet replacing old source packet.
+ std::memcpy(data, produce_data(), new_payload_size);
+
+ // Advance the encoder to next symbol.
+ produce_next();
+ }
+
+#if 0
+ if (i == k_) {
+ // Ensure repair are generated after k source packets
+ flush_repair();
+ }
+#endif
+
+ // Here we should produce all the repair packets
+ while (can_produce()) {
+ // The current index MUST be k_, because we enforce n - k repair to be
+ // produced after k sources
+ assert(current_index_ == k_);
+
+ buffer packet;
+ if (!buffer_callback_) {
+ // If no callback is installed, let's allocate a buffer from global pool
+ packet = core::PacketManager<>::getInstance().getMemBuf();
+ packet->append(produce_bytes());
+ } else {
+ // Otherwise let's ask a buffer to the caller.
+ packet = buffer_callback_(produce_bytes());
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Producing symbol of size " << produce_bytes();
+
+ // Copy symbol to packet buffer
+ std::memcpy(packet->writableData(), produce_data(), produce_bytes());
+
+ // Push symbol in repair_packets
+ packets_.emplace_back(0, std::move(packet));
+
+ // Advance the encoder
+ produce_next();
+ }
+
+ // Print number of unprotected symbols
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Number of unprotected symbols: " << unprotected_symbols();
+
+ // If we have generated repair symbols, let's notify caller via the installed
+ // callback
+ if (packets_.size()) {
+ assert(packets_.size() == n_ - k_);
+ fec_callback_(packets_);
+ packets_.clear();
+ current_index_ = 0;
+ }
+}
+
+RelyDecoder::RelyDecoder(uint32_t k, uint32_t n, uint32_t seq_offset)
+ : RelyBase(k, n, seq_offset) {
+ configure(kmtu, ktimeout, kmax_stream_size);
+}
+
+void RelyDecoder::onDataPacket(core::ContentObject &content_object,
+ uint32_t offset) {
+ // Adjust pointers to point to packet payload
+ auto data = content_object.writableData() + offset;
+ auto size = content_object.length() - offset;
+
+ // Pass payload to decoder
+ consume(data, size, getCurrentTime());
+
+ // Drain decoder if possible
+ while (can_produce()) {
+ // Get size of decoded packet
+ auto size = produce_bytes();
+
+ // Get buffer to copy packet in
+ auto packet = core::PacketManager<>::getInstance().getMemBuf();
+
+ // Copy buffer
+ packet->append(size);
+ std::memcpy(packet->writableData(), produce_data(), size);
+
+ // Read seq number
+ fec_header *h = reinterpret_cast<fec_header *>(packet->writableData());
+ uint32_t index = h->getSeqNumberBase();
+
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "The index written in the packet is " << index;
+
+ // Remove FEC header
+ packet->trimStart(sizeof(fec_header));
+
+ // Save packet in buffer
+ packets_.emplace_back(index, std::move(packet));
+
+ // Advance to next packet
+ produce_next();
+ }
+
+ // If we produced packets, lets notify the caller via the callback
+ if (packets_.size() > 0) {
+ fec_callback_(packets_);
+ packets_.clear();
+ }
+}
+
+} // namespace fec
+} // namespace protocol
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/fec/rely.h b/libtransport/src/protocols/fec/rely.h
new file mode 100644
index 000000000..bfbdb30bc
--- /dev/null
+++ b/libtransport/src/protocols/fec/rely.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/chrono_typedefs.h>
+#include <hicn/transport/utils/membuf.h>
+#include <protocols/fec/fec_info.h>
+#include <protocols/fec_base.h>
+
+#include <rely/decoder.hpp>
+#include <rely/encoder.hpp>
+
+#define RELY_DEBUG 0
+
+namespace transport {
+namespace protocol {
+namespace fec {
+
+/**
+ * @brief Table of used codes.
+ */
+#define foreach_rely_fec_type \
+ _(Rely, 1, 3) \
+ _(Rely, 2, 3) \
+ _(Rely, 4, 5) \
+ _(Rely, 4, 6) \
+ _(Rely, 4, 7) \
+ _(Rely, 6, 10) \
+ _(Rely, 8, 10) \
+ _(Rely, 8, 11) \
+ _(Rely, 8, 12) \
+ _(Rely, 8, 14) \
+ _(Rely, 8, 16) \
+ _(Rely, 8, 32) \
+ _(Rely, 10, 30) \
+ _(Rely, 10, 40) \
+ _(Rely, 10, 90) \
+ _(Rely, 16, 21) \
+ _(Rely, 16, 23) \
+ _(Rely, 16, 24) \
+ _(Rely, 16, 27) \
+ _(Rely, 17, 21) \
+ _(Rely, 17, 34) \
+ _(Rely, 32, 41) \
+ _(Rely, 32, 46) \
+ _(Rely, 32, 54) \
+ _(Rely, 34, 42) \
+ _(Rely, 35, 70) \
+ _(Rely, 52, 62)
+
+/**
+ * @brief Base class to store common fields.
+ */
+class RelyBase : public virtual FECBase {
+ protected:
+ static const constexpr size_t kmax_stream_size = 125U;
+ static const constexpr size_t kmtu = 1500U;
+ static const constexpr size_t ktimeout = 100U;
+ /**
+ * @brief FEC Header, added to each packet to get sequence number upon
+ * decoding operations. It may be removed once we know the meaning of the
+ * fields in the rely header.
+ */
+ struct fec_header {
+ uint32_t seq_number;
+
+ void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); }
+ uint32_t getSeqNumberBase() { return ntohl(seq_number); }
+ };
+
+ /**
+ * @brief Construct a new Rely Base object.
+ *
+ * @param k The number of source symbol needed to generate n - k repair
+ * symbols
+ * @param n The sum of source packets and repair packets in a `block`
+ * @param seq_offset offset to use if production suffixes starts from an index
+ * != 0
+ */
+ RelyBase(uint32_t k, uint32_t n, uint32_t seq_offset = 0)
+ : k_(k),
+ n_(n),
+ seq_offset_(seq_offset % n_),
+ current_index_(seq_offset)
+#if RELY_DEBUG
+ ,
+ time_(0)
+#endif
+ {
+ }
+
+ /**
+ * @brief Get the current time in milliseconds
+ *
+ * @return int64_t Current time in milliseconds
+ */
+ int64_t getCurrentTime() {
+ // Get the current time
+#if RELY_DEBUG
+ return time_++;
+#else
+ auto _time = utils::SteadyClock::now().time_since_epoch();
+ auto time = std::chrono::duration_cast<utils::Milliseconds>(_time).count();
+ return time;
+#endif
+ }
+
+ protected:
+ uint32_t k_;
+ uint32_t n_;
+ std::uint32_t seq_offset_;
+ /**
+ * @brief Vector of packets to be passed to caller callbacks. For encoder it
+ * will contain the repair packets, for decoder the recovered sources.
+ */
+ std::vector<std::pair<uint32_t, buffer>> packets_;
+
+ /**
+ * @brief Current index to be used for local packet count.
+ *
+ */
+ uint32_t current_index_;
+#if RELY_DEBUG
+ uint32_t time_;
+#endif
+};
+
+/**
+ * @brief The Rely Encoder implementation.
+ *
+ */
+class RelyEncoder : private RelyBase,
+ private rely::encoder,
+ public ProducerFEC {
+ public:
+ RelyEncoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
+ /**
+ * Producers will call this function when they produce a data packet.
+ */
+ void onPacketProduced(core::ContentObject &content_object,
+ uint32_t offset) override;
+
+ /**
+ * @brief Get the fec header size, if added to source packets
+ */
+ std::size_t getFecHeaderSize() override {
+ return header_bytes() + sizeof(fec_header) + 4;
+ }
+
+ void reset() override {}
+};
+
+class RelyDecoder : private RelyBase,
+ private rely::decoder,
+ public ConsumerFEC {
+ public:
+ RelyDecoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
+
+ /**
+ * Consumers will call this function when they receive a data packet
+ */
+ void onDataPacket(core::ContentObject &content_object,
+ uint32_t offset) override;
+
+ /**
+ * @brief Get the fec header size, if added to source packets
+ */
+ std::size_t getFecHeaderSize() override {
+ return header_bytes() + sizeof(fec_header);
+ }
+
+ void reset() override {}
+};
+
+} // namespace fec
+
+} // namespace protocol
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/fec/rs.cc b/libtransport/src/protocols/fec/rs.cc
new file mode 100644
index 000000000..2c23d515d
--- /dev/null
+++ b/libtransport/src/protocols/fec/rs.cc
@@ -0,0 +1,418 @@
+
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <glog/logging.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec/fec.h>
+#include <protocols/fec/rs.h>
+
+#include <cassert>
+
+namespace transport {
+namespace protocol {
+namespace fec {
+
+BlockCode::BlockCode(uint32_t k, uint32_t n, uint32_t seq_offset,
+ struct fec_parms *code, rs &params)
+ : Packets(),
+ k_(k),
+ n_(n),
+ seq_offset_(seq_offset),
+ code_(code),
+ max_buffer_size_(0),
+ current_block_size_(0),
+ to_decode_(false),
+ params_(params) {
+ sorted_index_.reserve(n);
+ UNUSED(seq_offset_);
+}
+
+bool BlockCode::addRepairSymbol(const fec::buffer &packet, uint32_t i,
+ uint32_t offset) {
+ // Get index
+ to_decode_ = true;
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding symbol of size " << packet->length();
+ return addSymbol(packet, i, offset,
+ packet->length() - sizeof(fec_header) - offset);
+}
+
+bool BlockCode::addSourceSymbol(const fec::buffer &packet, uint32_t i,
+ uint32_t offset) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding source symbol of size "
+ << packet->length() << ", offset " << offset;
+ return addSymbol(packet, i, offset, packet->length() - offset);
+}
+
+bool BlockCode::addSymbol(const fec::buffer &packet, uint32_t i,
+ uint32_t offset, std::size_t size) {
+ if (size > max_buffer_size_) {
+ max_buffer_size_ = size;
+ }
+
+ operator[](current_block_size_++) = std::make_tuple(i, packet, offset);
+
+ if (current_block_size_ >= k_) {
+ if (to_decode_) {
+ decode();
+ } else {
+ encode();
+ }
+
+ clear();
+ return false;
+ }
+
+ return true;
+}
+
+void BlockCode::encode() {
+ gf *data[n_];
+ uint32_t base = std::get<0>(operator[](0));
+
+ // Set packet length in first 2 bytes
+ for (uint32_t i = 0; i < k_; i++) {
+ auto &packet = std::get<1>(operator[](i));
+ auto offset = std::get<2>(operator[](i));
+
+ auto ret =
+ packet->ensureCapacityAndFillUnused(max_buffer_size_ + offset, 0);
+ if (TRANSPORT_EXPECT_FALSE(ret == false)) {
+ throw errors::RuntimeException(
+ "Provided packet is not suitable to be used as FEC source packet. "
+ "Aborting.");
+ }
+
+ // Buffers should hold 2 *after* the padding, in order to be
+ // able to set the length for the encoding operation.
+ // packet->trimStart(offset);
+ uint16_t *length = reinterpret_cast<uint16_t *>(packet->writableData() +
+ max_buffer_size_ + offset);
+ auto buffer_length = packet->length() - offset;
+ *length = htons(buffer_length);
+
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Current buffer size: " << packet->length();
+
+ data[i] = packet->writableData() + offset;
+ }
+
+ // Finish to fill source block with the buffers to hold the repair symbols
+ auto length = max_buffer_size_ + sizeof(fec_header) + LEN_SIZE_BYTES;
+ for (uint32_t i = k_; i < n_; i++) {
+ buffer packet;
+ if (!params_.buffer_callback_) {
+ // If no callback is installed, let's allocate a buffer from global pool
+ packet = core::PacketManager<>::getInstance().getMemBuf();
+ packet->append(length);
+ } else {
+ // Otherwise let's ask a buffer to the caller.
+ packet = params_.buffer_callback_(length);
+ }
+
+ fec_header *fh = reinterpret_cast<fec_header *>(packet->writableData());
+
+ fh->setSeqNumberBase(base);
+ fh->setNFecSymbols(n_ - k_);
+ fh->setEncodedSymbolId(i);
+ fh->setSourceBlockLen(n_);
+
+ packet->trimStart(sizeof(fec_header));
+
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Current symbol size: " << packet->length();
+
+ data[i] = packet->writableData();
+ operator[](i) = std::make_tuple(i, std::move(packet), uint32_t(0));
+ }
+
+ // Generate repair symbols and put them in corresponding buffers
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Calling encode with max_buffer_size_ = " << max_buffer_size_;
+ for (uint32_t i = k_; i < n_; i++) {
+ fec_encode(code_, data, data[i], i, max_buffer_size_ + LEN_SIZE_BYTES);
+ }
+
+ // Re-include header in repair packets
+ for (uint32_t i = k_; i < n_; i++) {
+ auto &packet = std::get<1>(operator[](i));
+ packet->prepend(sizeof(fec_header));
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Produced repair symbol of size = " << packet->length();
+ }
+}
+
+void BlockCode::decode() {
+ gf *data[k_];
+ uint32_t index[k_];
+
+ for (uint32_t i = 0; i < k_; i++) {
+ auto &packet = std::get<1>(operator[](i));
+ index[i] = std::get<0>(operator[](i));
+ auto offset = std::get<2>(operator[](i));
+ sorted_index_[i] = index[i];
+
+ if (index[i] < k_) {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "DECODE SOURCE - index " << index[i]
+ << " - Current buffer size: " << packet->length();
+ // This is a source packet. We need to fill
+ // additional space to 0 and append the length
+
+ // Buffers should hold 2 bytes at the end, in order to be
+ // able to set the length for the encoding operation
+ packet->trimStart(offset);
+ packet->ensureCapacityAndFillUnused(max_buffer_size_, 0);
+ uint16_t *length = reinterpret_cast<uint16_t *>(
+ packet->writableData() + max_buffer_size_ - LEN_SIZE_BYTES);
+
+ *length = htons(packet->length());
+ } else {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "DECODE SYMBOL - index " << index[i]
+ << " - Current buffer size: " << packet->length();
+ packet->trimStart(sizeof(fec_header) + offset);
+ }
+
+ data[i] = packet->writableData();
+ }
+
+ // We decode the source block
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Calling decode with max_buffer_size_ = " << max_buffer_size_;
+ fec_decode(code_, data, reinterpret_cast<int *>(index), max_buffer_size_);
+
+ // Find the index in the block for recovered packets
+ for (uint32_t i = 0; i < k_; i++) {
+ if (index[i] != i) {
+ for (uint32_t j = 0; j < k_; j++)
+ if (sorted_index_[j] == uint32_t(index[i])) {
+ sorted_index_[j] = i;
+ }
+ }
+ }
+
+ // Reorder block by index with in-place sorting
+ for (uint32_t i = 0; i < k_; i++) {
+ for (uint32_t j = sorted_index_[i]; j != i; j = sorted_index_[i]) {
+ std::swap(sorted_index_[j], sorted_index_[i]);
+ std::swap(operator[](j), operator[](i));
+ }
+ }
+
+ // Adjust length according to the one written in the source packet
+ for (uint32_t i = 0; i < k_; i++) {
+ auto &packet = std::get<1>(operator[](i));
+ uint16_t *length = reinterpret_cast<uint16_t *>(
+ packet->writableData() + max_buffer_size_ - LEN_SIZE_BYTES);
+ packet->setLength(ntohs(*length));
+ }
+}
+
+void BlockCode::clear() {
+ current_block_size_ = 0;
+ max_buffer_size_ = 0;
+ sorted_index_.clear();
+ to_decode_ = false;
+}
+
+void rs::MatrixDeleter::operator()(struct fec_parms *params) {
+ fec_free(params);
+}
+
+rs::Codes rs::createCodes() {
+ Codes ret;
+
+#define _(name, k, n) \
+ ret.emplace(std::make_pair(k, n), Matrix(fec_new(k, n), MatrixDeleter()));
+ foreach_rs_fec_type
+#undef _
+
+ return ret;
+}
+
+rs::Codes rs::codes_ = createCodes();
+
+rs::rs(uint32_t k, uint32_t n, uint32_t seq_offset)
+ : k_(k), n_(n), seq_offset_(seq_offset % n) {}
+
+RSEncoder::RSEncoder(uint32_t k, uint32_t n, uint32_t seq_offset)
+ : rs(k, n, seq_offset),
+ current_code_(codes_[std::make_pair(k, n)].get()),
+ source_block_(k_, n_, seq_offset_, current_code_, *this) {}
+
+void RSEncoder::consume(const fec::buffer &packet, uint32_t index,
+ uint32_t offset) {
+ if (!source_block_.addSourceSymbol(packet, index, offset)) {
+ std::vector<std::pair<uint32_t, buffer>> repair_packets;
+ for (uint32_t i = k_; i < n_; i++) {
+ repair_packets.emplace_back(std::move(std::get<0>(source_block_[i])),
+ std::move(std::get<1>(source_block_[i])));
+ }
+
+ fec_callback_(repair_packets);
+ }
+}
+
+void RSEncoder::onPacketProduced(core::ContentObject &content_object,
+ uint32_t offset) {
+ consume(content_object.shared_from_this(),
+ content_object.getName().getSuffix(), offset);
+}
+
+RSDecoder::RSDecoder(uint32_t k, uint32_t n, uint32_t seq_offset)
+ : rs(k, n, seq_offset) {}
+
+void RSDecoder::recoverPackets(SourceBlocks::iterator &src_block_it) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "recoverPackets for " << k_;
+ auto &src_block = src_block_it->second;
+ std::vector<std::pair<uint32_t, buffer>> source_packets(k_);
+ for (uint32_t i = 0; i < src_block.getK(); i++) {
+ source_packets[i] = std::make_pair(src_block_it->first + i,
+ std::move(std::get<1>(src_block[i])));
+ }
+
+ setProcessed(src_block_it->first);
+
+ fec_callback_(source_packets);
+ processed_source_blocks_.emplace(src_block_it->first);
+
+ auto it = parked_packets_.find(src_block_it->first);
+ if (it != parked_packets_.end()) {
+ parked_packets_.erase(it);
+ }
+
+ src_blocks_.erase(src_block_it);
+}
+
+void RSDecoder::consumeSource(const fec::buffer &packet, uint32_t index,
+ uint32_t offset) {
+ // Normalize index
+ assert(index >= seq_offset_);
+ auto i = (index - seq_offset_) % n_;
+
+ // Get base
+ uint32_t base = index - i;
+
+ if (processed(base)) {
+ return;
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Decoder consume called for source symbol. BASE = " << base
+ << ", index = " << index << " and i = " << i;
+
+ // check if a source block already exist for this symbol. If it does not
+ // exist, we lazily park this packet until we receive a repair symbol for the
+ // same block. This is done for 2 reason:
+ // 1) If we receive all the source packets of a block, we do not need to
+ // recover anything.
+ // 2) Sender may change n and k at any moment, so we construct the source
+ // block based on the (n, k) values written in the fec header. This is
+ // actually not used right now, since we use fixed value of n and k passed
+ // at construction time, but it paves the ground for a more dynamic
+ // protocol that may come in the future.
+ auto it = src_blocks_.find(base);
+ if (it != src_blocks_.end()) {
+ auto ret = it->second.addSourceSymbol(packet, i, offset);
+ if (!ret) {
+ recoverPackets(it);
+ }
+ } else {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Adding to parked source packets";
+ auto ret = parked_packets_.emplace(
+ base, std::vector<std::pair<buffer, uint32_t>>());
+ ret.first->second.emplace_back(packet, i);
+
+ if (ret.first->second.size() >= k_) {
+ setProcessed(ret.first->first);
+ parked_packets_.erase(ret.first);
+ }
+ }
+}
+
+void RSDecoder::consumeRepair(const fec::buffer &packet, uint32_t offset) {
+ // Repair symbol! Get index and base source block.
+ fec_header *h =
+ reinterpret_cast<fec_header *>(packet->writableData() + offset);
+ auto i = h->getEncodedSymbolId();
+ auto base = h->getSeqNumberBase();
+ auto n = h->getSourceBlockLen();
+ auto k = n - h->getNFecSymbols();
+
+ if (processed(base)) {
+ return;
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Decoder consume called for repair symbol. BASE = " << base
+ << ", index = " << base + i << " and i = " << i << ". K=" << k
+ << ", N=" << n;
+
+ // check if a source block already exist for this symbol
+ auto it = src_blocks_.find(base);
+ if (it == src_blocks_.end()) {
+ // Create new source block
+ auto code_it = codes_.find(std::make_pair(k, n));
+ if (code_it == codes_.end()) {
+ LOG(ERROR) << "Code for k = " << k << " and n = " << n
+ << " does not exist.";
+ return;
+ }
+
+ auto emplace_result = src_blocks_.emplace(
+ base, BlockCode(k, n, seq_offset_, code_it->second.get(), *this));
+ it = emplace_result.first;
+
+ // Check in the parked packets and insert any packet that is part of this
+ // source block
+
+ auto it2 = parked_packets_.find(base);
+ if (it2 != parked_packets_.end()) {
+ for (auto &packet_index : it2->second) {
+ auto ret = it->second.addSourceSymbol(packet_index.first,
+ packet_index.second, offset);
+ if (!ret) {
+ recoverPackets(it);
+ // Finish to delete packets in same source block that were
+ // eventually not used
+ return;
+ }
+ }
+ }
+ }
+
+ auto ret = it->second.addRepairSymbol(packet, i, offset);
+ if (!ret) {
+ recoverPackets(it);
+ }
+}
+
+void RSDecoder::onDataPacket(core::ContentObject &content_object,
+ uint32_t offset) {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Calling fec for data packet " << content_object.getName()
+ << ". Offset: " << offset;
+
+ auto suffix = content_object.getName().getSuffix();
+
+ if (isSymbol(suffix)) {
+ consumeRepair(content_object.shared_from_this(), offset);
+ } else {
+ consumeSource(content_object.shared_from_this(), suffix, offset);
+ }
+}
+
+} // namespace fec
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/core/rs.h b/libtransport/src/protocols/fec/rs.h
index 9a8c43e4d..e159ad9f7 100644
--- a/libtransport/src/core/rs.h
+++ b/libtransport/src/protocols/fec/rs.h
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-#ifndef _WIN32
+#pragma once
+
#include <arpa/inet.h>
-#endif
+#include <hicn/transport/portability/c_portability.h>
#include <hicn/transport/utils/membuf.h>
+#include <protocols/fec/fec_info.h>
#include <protocols/fec_base.h>
#include <array>
@@ -27,13 +29,43 @@
#include <vector>
namespace transport {
-namespace core {
+namespace protocol {
namespace fec {
+#define foreach_rs_fec_type \
+ _(RS, 1, 3) \
+ _(RS, 4, 5) \
+ _(RS, 4, 6) \
+ _(RS, 4, 7) \
+ _(RS, 6, 10) \
+ _(RS, 8, 10) \
+ _(RS, 8, 11) \
+ _(RS, 8, 12) \
+ _(RS, 8, 14) \
+ _(RS, 8, 16) \
+ _(RS, 8, 32) \
+ _(RS, 10, 30) \
+ _(RS, 10, 40) \
+ _(RS, 10, 60) \
+ _(RS, 10, 90) \
+ _(RS, 16, 18) \
+ _(RS, 16, 21) \
+ _(RS, 16, 23) \
+ _(RS, 16, 24) \
+ _(RS, 16, 27) \
+ _(RS, 17, 21) \
+ _(RS, 17, 34) \
+ _(RS, 32, 36) \
+ _(RS, 32, 41) \
+ _(RS, 32, 46) \
+ _(RS, 32, 54) \
+ _(RS, 34, 42) \
+ _(RS, 35, 70) \
+ _(RS, 52, 62)
+
static const constexpr uint16_t MAX_SOURCE_BLOCK_SIZE = 128;
-using buffer = typename utils::MemBuf::Ptr;
/**
* We use a std::array in place of std::vector to avoid to allocate a new vector
* in the heap every time we build a new source block, which would be bad if
@@ -41,7 +73,9 @@ using buffer = typename utils::MemBuf::Ptr;
* std::array allows to be constructed in place, saving the allocation at the
* price os knowing in advance its size.
*/
-using Packets = std::array<std::pair<uint32_t, buffer>, MAX_SOURCE_BLOCK_SIZE>;
+using Packets = std::array<std::tuple</* index */ uint32_t, /* buffer */ buffer,
+ uint32_t /* offset */>,
+ MAX_SOURCE_BLOCK_SIZE>;
/**
* FEC Header, prepended to symbol packets.
@@ -82,6 +116,8 @@ struct fec_header {
uint8_t getNFecSymbols() { return n_fec_symbols; }
};
+class rs;
+
/**
* This class models the source block itself.
*/
@@ -93,17 +129,20 @@ class BlockCode : public Packets {
static constexpr std::size_t LEN_SIZE_BYTES = 2;
public:
- BlockCode(uint32_t k, uint32_t n, struct fec_parms *code);
+ BlockCode(uint32_t k, uint32_t n, uint32_t seq_offset, struct fec_parms *code,
+ rs &params);
/**
* Add a repair symbol to the dource block.
*/
- bool addRepairSymbol(const fec::buffer &packet, uint32_t i);
+ bool addRepairSymbol(const fec::buffer &packet, uint32_t i,
+ uint32_t offset = 0);
/**
* Add a source symbol to the source block.
*/
- bool addSourceSymbol(const fec::buffer &packet, uint32_t i);
+ bool addSourceSymbol(const fec::buffer &packet, uint32_t i,
+ uint32_t offset = 0);
/**
* Get current length of source block.
@@ -129,7 +168,8 @@ class BlockCode : public Packets {
/**
* Add symbol to source block
**/
- bool addSymbol(const fec::buffer &packet, uint32_t i, std::size_t size);
+ bool addSymbol(const fec::buffer &packet, uint32_t i, uint32_t offset,
+ std::size_t size);
/**
* Starting from k source symbols, get the n - k repair symbols
@@ -147,11 +187,13 @@ class BlockCode : public Packets {
private:
uint32_t k_;
uint32_t n_;
+ uint32_t seq_offset_;
struct fec_parms *code_;
std::size_t max_buffer_size_;
std::size_t current_block_size_;
std::vector<uint32_t> sorted_index_;
bool to_decode_;
+ rs &params_;
};
/**
@@ -166,7 +208,9 @@ class BlockCode : public Packets {
* message later to negotiate them, so that decoder cah dynamically change them
* during the download.
*/
-class rs {
+class rs : public virtual FECBase {
+ friend class BlockCode;
+
/**
* Deleter for static preallocated reed-solomon parameters.
*/
@@ -190,7 +234,7 @@ class rs {
* Custom hash function for (k, n) pair.
*/
struct CodeHasher {
- std::size_t operator()(const transport::core::fec::rs::Code &code) const {
+ std::size_t operator()(const Code &code) const {
uint64_t ret = uint64_t(code.first) << 32 | uint64_t(code.second);
return std::hash<uint64_t>{}(ret);
}
@@ -221,16 +265,13 @@ class rs {
using Codes = std::unordered_map<Code, Matrix, CodeHasher>;
public:
- rs(uint32_t k, uint32_t n);
+ rs(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
~rs() = default;
- /**
- * Set callback to call after packet encoding / decoding
- */
- void setFECCallback(const PacketsReady &callback);
-
virtual void clear() { processed_source_blocks_.clear(); }
+ bool isSymbol(uint32_t index) { return ((index - seq_offset_) % n_) >= k_; }
+
private:
/**
* Create reed-solomon codes at program startup.
@@ -243,9 +284,13 @@ class rs {
processed_source_blocks_.end();
}
+ void setProcessed(SNBase seq_base) {
+ processed_source_blocks_.emplace(seq_base);
+ }
+
std::uint32_t k_;
std::uint32_t n_;
- PacketsReady fec_callback_;
+ std::uint32_t seq_offset_;
/**
* Keep track of processed source blocks
@@ -259,19 +304,29 @@ class rs {
* The reed-solomon encoder. It is feeded with source symbols and it provide
* repair-symbols through the fec_callback_
*/
-class encoder : public rs {
+class RSEncoder : public rs, public ProducerFEC {
public:
- encoder(uint32_t k, uint32_t n);
+ RSEncoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
/**
* Always consume source symbols.
*/
- void consume(const fec::buffer &packet, uint32_t index);
+ void consume(const fec::buffer &packet, uint32_t index, uint32_t offset = 0);
+
+ void onPacketProduced(core::ContentObject &content_object,
+ uint32_t offset) override;
+
+ /**
+ * @brief Get the fec header size, if added to source packets
+ */
+ std::size_t getFecHeaderSize() override { return 0; }
void clear() override {
rs::clear();
source_block_.clear();
}
+ void reset() override { clear(); }
+
private:
struct fec_parms *current_code_;
/**
@@ -286,19 +341,31 @@ class encoder : public rs {
* The reed-solomon encoder. It is feeded with source/repair symbols and it
* provides the original source symbols through the fec_callback_
*/
-class decoder : public rs {
+class RSDecoder : public rs, public ConsumerFEC {
public:
- decoder(uint32_t k, uint32_t n);
+ RSDecoder(uint32_t k, uint32_t n, uint32_t seq_offset = 0);
/**
* Consume source symbol
*/
- void consume(const fec::buffer &packet, uint32_t i);
+ void consumeSource(const fec::buffer &packet, uint32_t i,
+ uint32_t offset = 0);
/**
* Consume repair symbol
*/
- void consume(const fec::buffer &packet);
+ void consumeRepair(const fec::buffer &packet, uint32_t offset = 0);
+
+ /**
+ * Consumers will call this function when they receive a data packet
+ */
+ void onDataPacket(core::ContentObject &content_object,
+ uint32_t offset) override;
+
+ /**
+ * @brief Get the fec header size, if added to source packets
+ */
+ std::size_t getFecHeaderSize() override { return 0; }
/**
* Clear decoder to reuse
@@ -309,6 +376,8 @@ class decoder : public rs {
parked_packets_.clear();
}
+ void reset() override { clear(); }
+
private:
void recoverPackets(SourceBlocks::iterator &src_block_it);
@@ -335,6 +404,6 @@ class decoder : public rs {
} // namespace fec
-} // namespace core
+} // namespace protocol
} // namespace transport
diff --git a/libtransport/src/interfaces/rtc_socket_producer.cc b/libtransport/src/protocols/fec_base.cc
index 07d72db7e..9252bc473 100644
--- a/libtransport/src/interfaces/rtc_socket_producer.cc
+++ b/libtransport/src/protocols/fec_base.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,17 +13,12 @@
* limitations under the License.
*/
-#include <hicn/transport/interfaces/rtc_socket_producer.h>
-
-#include <implementation/rtc_socket_producer.h>
+#include <protocols/fec/rs.h>
+#include <protocols/fec_base.h>
namespace transport {
-namespace interface {
-
-RTCProducerSocket::RTCProducerSocket() : ProducerSocket(false) {
- socket_ = std::make_unique<implementation::RTCProducerSocket>(this);
-}
-
-} // namespace interface
+namespace protocol {
-} // namespace transport
+namespace fec {} // namespace fec
+} // namespace protocol
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/fec_base.h b/libtransport/src/protocols/fec_base.h
index a135c474f..a1929d85e 100644
--- a/libtransport/src/protocols/fec_base.h
+++ b/libtransport/src/protocols/fec_base.h
@@ -16,71 +16,88 @@
#pragma once
#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
#include <functional>
namespace transport {
namespace protocol {
-/**
- * Interface classes to integrate FEC inside any producer transport protocol
- */
-class ProducerFECBase {
+namespace fec {
+
+using buffer = typename utils::MemBuf::Ptr;
+using BufferArray = std::vector<std::pair<uint32_t, buffer>>;
+
+class FECBase {
public:
+ virtual ~FECBase() = default;
/**
- * Callback, to be called by implementations as soon as a repair packet is
- * ready.
+ * Callback to be called after the encode or the decode operations. In the
+ * former case it will contain the symbols, while in the latter the sources.
*/
- using RepairPacketsReady =
- std::function<void(std::vector<core::ContentObject::Ptr> &)>;
+ using PacketsReady = std::function<void(BufferArray &)>;
/**
- * Producers will call this function upon production of a new packet.
+ * Callback to be called when a new buffer (for encoding / decoding) needs to
+ * be allocated.
*/
- virtual void onPacketProduced(const core::ContentObject &content_object) = 0;
+ using BufferRequested = std::function<buffer(std::size_t size)>;
/**
- * Set callback to signal production protocol the repair packet is ready.
+ * @brief Get size of FEC header.
*/
- void setFECCallback(const RepairPacketsReady &on_repair_packet) {
- rep_packet_ready_callback_ = on_repair_packet;
+ virtual std::size_t getFecHeaderSize() = 0;
+
+ /**
+ * Set callback to call after packet encoding / decoding
+ */
+ template <typename Handler>
+ void setFECCallback(Handler &&callback) {
+ fec_callback_ = std::forward<Handler>(callback);
}
+ /**
+ * Set a callback to request a buffer.
+ */
+ template <typename Handler>
+ void setBufferCallback(Handler &&buffer_callback) {
+ buffer_callback_ = buffer_callback;
+ }
+
+ virtual void reset() = 0;
+
protected:
- RepairPacketsReady rep_packet_ready_callback_;
+ PacketsReady fec_callback_{0};
+ BufferRequested buffer_callback_{0};
};
/**
- * Interface classes to integrate FEC inside any consumer transport protocol
+ * Interface classes to integrate FEC inside any producer transport protocol
*/
-class ConsumerFECBase {
+class ProducerFEC : public virtual FECBase {
public:
+ virtual ~ProducerFEC() = default;
/**
- * Callback, to be called by implemrntations as soon as a packet is recovered.
+ * Producers will call this function upon production of a new packet.
*/
- using OnPacketsRecovered =
- std::function<void(std::vector<core::ContentObject::Ptr> &)>;
+ virtual void onPacketProduced(core::ContentObject &content_object,
+ uint32_t offset) = 0;
+};
- /**
- * Consumers will call this function when they receive a FEC packet.
- */
- virtual void onFECPacket(const core::ContentObject &content_object) = 0;
+/**
+ * Interface classes to integrate FEC inside any consumer transport protocol
+ */
+class ConsumerFEC : public virtual FECBase {
+ public:
+ virtual ~ConsumerFEC() = default;
/**
* Consumers will call this function when they receive a data packet
*/
- virtual void onDataPacket(const core::ContentObject &content_object) = 0;
-
- /**
- * Set callback to signal consumer protocol the repair packet is ready.
- */
- void setFECCallback(const OnPacketsRecovered &on_repair_packet) {
- packet_recovered_callback_ = on_repair_packet;
- }
-
- protected:
- OnPacketsRecovered packet_recovered_callback_;
+ virtual void onDataPacket(core::ContentObject &content_object,
+ uint32_t offset) = 0;
};
+} // namespace fec
} // namespace protocol
} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/fec_utils.h b/libtransport/src/protocols/fec_utils.h
new file mode 100644
index 000000000..d70ff1c09
--- /dev/null
+++ b/libtransport/src/protocols/fec_utils.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/errors/not_implemented_exception.h>
+#include <protocols/fec/rs.h>
+
+#if ENABLE_RELY
+#include <protocols/fec/rely.h>
+#endif
+
+#include <functional>
+
+namespace transport {
+namespace protocol {
+
+namespace fec {
+
+#if ENABLE_RELY
+#define foreach_fec_type foreach_rs_fec_type foreach_rely_fec_type
+#else
+#define foreach_fec_type foreach_rs_fec_type
+#endif
+
+#define ENUM_FROM_MACRO(name, k, n) name##_K##k##_N##n
+#define ENUM_FROM_MACRO_STR(name, k, n) #name "_K" #k "_N" #n
+
+enum class FECType : uint8_t {
+#define _(name, k, n) ENUM_FROM_MACRO(name, k, n),
+ foreach_fec_type
+#undef _
+ UNKNOWN
+};
+
+#define ENUM_FROM_MACRO2(name, k, n) FECType::ENUM_FROM_MACRO(name, k, n)
+
+class FECUtils {
+ public:
+ static FECType fecTypeFromString(const char *fec_type) {
+#define _(name, k, n) \
+ do { \
+ if (strncmp(fec_type, ENUM_FROM_MACRO_STR(name, k, n), \
+ strlen(ENUM_FROM_MACRO_STR(name, k, n))) == 0) { \
+ return ENUM_FROM_MACRO2(name, k, n); \
+ } \
+ } while (0);
+ foreach_fec_type
+#undef _
+
+ return FECType::UNKNOWN;
+ }
+
+ static bool isFec(FECType fec_type, uint32_t index, uint32_t seq_offset = 0) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return FecInfo<Code<k, n>>::isFec(index - (seq_offset % n));
+
+ foreach_fec_type
+#undef _
+ default : return false;
+ }
+ }
+
+ static uint32_t nextSource(FECType fec_type, uint32_t index,
+ uint32_t seq_offset = 0) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return FecInfo<Code<k, n>>::nextSource(index) + (seq_offset % n);
+
+ foreach_fec_type
+#undef _
+ default : throw std::runtime_error("Unknown fec type");
+ }
+ }
+
+ static uint32_t getSourceSymbols(FECType fec_type) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return k;
+ foreach_fec_type
+#undef _
+ default : throw std::runtime_error("Unknown fec type");
+ }
+ }
+
+ static uint32_t getBlockSymbols(FECType fec_type) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return n;
+ foreach_fec_type
+#undef _
+ default : throw std::runtime_error("Unknown fec type");
+ }
+ }
+
+ static std::unique_ptr<ProducerFEC> getEncoder(FECType fec_type,
+ uint32_t seq_offset = 0) {
+ return factoryEncoder(fec_type, seq_offset);
+ }
+
+ static std::unique_ptr<ConsumerFEC> getDecoder(FECType fec_type,
+ uint32_t seq_offset = 0) {
+ return factoryDencoder(fec_type, seq_offset);
+ }
+
+ private:
+ static std::unique_ptr<ProducerFEC> factoryEncoder(FECType fec_type,
+ uint32_t seq_offset) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return std::make_unique<name##Encoder>(k, n, seq_offset);
+
+ foreach_fec_type
+#undef _
+ default : throw std::runtime_error("Unknown fec type");
+ }
+ }
+
+ static std::unique_ptr<ConsumerFEC> factoryDencoder(FECType fec_type,
+ uint32_t seq_offset) {
+ switch (fec_type) {
+#define _(name, k, n) \
+ case ENUM_FROM_MACRO2(name, k, n): \
+ return std::make_unique<name##Decoder>(k, n, seq_offset);
+
+ foreach_fec_type
+#undef _
+ default : throw std::runtime_error("Unknown fec type");
+ }
+ }
+}; // namespace fec
+
+} // namespace fec
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/protocols/incremental_indexer.h b/libtransport/src/protocols/incremental_indexer.h
deleted file mode 100644
index d7760f8e6..000000000
--- a/libtransport/src/protocols/incremental_indexer.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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/errors.h>
-#include <hicn/transport/interfaces/callbacks.h>
-#include <hicn/transport/auth/verifier.h>
-#include <hicn/transport/utils/literals.h>
-#include <implementation/socket_consumer.h>
-#include <protocols/indexer.h>
-#include <protocols/reassembly.h>
-
-#include <deque>
-
-namespace transport {
-
-namespace interface {
-class ConsumerSocket;
-}
-
-namespace protocol {
-
-class Reassembly;
-class TransportProtocol;
-
-class IncrementalIndexer : public Indexer {
- public:
- IncrementalIndexer(implementation::ConsumerSocket *icn_socket,
- TransportProtocol *transport, Reassembly *reassembly)
- : socket_(icn_socket),
- reassembly_(reassembly),
- transport_protocol_(transport),
- final_suffix_(std::numeric_limits<uint32_t>::max()),
- first_suffix_(0),
- next_download_suffix_(0),
- next_reassembly_suffix_(0),
- verifier_(nullptr) {
- if (reassembly_) {
- reassembly_->setIndexer(this);
- }
- socket_->getSocketOption(implementation::GeneralTransportOptions::VERIFIER,
- verifier_);
- }
-
- IncrementalIndexer(const IncrementalIndexer &) = delete;
-
- IncrementalIndexer(IncrementalIndexer &&other)
- : socket_(other.socket_),
- reassembly_(other.reassembly_),
- transport_protocol_(other.transport_protocol_),
- final_suffix_(other.final_suffix_),
- first_suffix_(other.first_suffix_),
- next_download_suffix_(other.next_download_suffix_),
- next_reassembly_suffix_(other.next_reassembly_suffix_),
- verifier_(nullptr) {
- if (reassembly_) {
- reassembly_->setIndexer(this);
- }
- socket_->getSocketOption(implementation::GeneralTransportOptions::VERIFIER,
- verifier_);
- }
-
- virtual ~IncrementalIndexer() {}
-
- TRANSPORT_ALWAYS_INLINE virtual void reset(
- std::uint32_t offset = 0) override {
- final_suffix_ = std::numeric_limits<uint32_t>::max();
- next_download_suffix_ = offset;
- next_reassembly_suffix_ = offset;
- }
-
- /**
- * Retrieve from the manifest the next suffix to retrieve.
- */
- TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextSuffix() override {
- return next_download_suffix_ <= final_suffix_ ? next_download_suffix_++
- : IndexManager::invalid_index;
- }
-
- TRANSPORT_ALWAYS_INLINE virtual void setFirstSuffix(
- uint32_t suffix) override {
- first_suffix_ = suffix;
- }
-
- /**
- * Retrive the next segment to be reassembled.
- */
- TRANSPORT_ALWAYS_INLINE virtual uint32_t getNextReassemblySegment() override {
- return next_reassembly_suffix_ <= final_suffix_
- ? next_reassembly_suffix_++
- : IndexManager::invalid_index;
- }
-
- TRANSPORT_ALWAYS_INLINE virtual bool isFinalSuffixDiscovered() override {
- return final_suffix_ != std::numeric_limits<uint32_t>::max();
- }
-
- TRANSPORT_ALWAYS_INLINE virtual uint32_t getFinalSuffix() override {
- return final_suffix_;
- }
-
- void onContentObject(core::Interest &interest,
- core::ContentObject &content_object) override;
-
- TRANSPORT_ALWAYS_INLINE void setReassembly(Reassembly *reassembly) {
- reassembly_ = reassembly;
-
- if (reassembly_) {
- reassembly_->setIndexer(this);
- }
- }
-
- protected:
- implementation::ConsumerSocket *socket_;
- Reassembly *reassembly_;
- TransportProtocol *transport_protocol_;
- uint32_t final_suffix_;
- uint32_t first_suffix_;
- uint32_t next_download_suffix_;
- uint32_t next_reassembly_suffix_;
- std::shared_ptr<auth::Verifier> verifier_;
-};
-
-} // namespace protocol
-} // namespace transport
diff --git a/libtransport/src/protocols/incremental_indexer.cc b/libtransport/src/protocols/incremental_indexer_bytestream.cc
index 95daa0a3e..cc302a98a 100644
--- a/libtransport/src/protocols/incremental_indexer.cc
+++ b/libtransport/src/protocols/incremental_indexer_bytestream.cc
@@ -15,18 +15,21 @@
#include <hicn/transport/interfaces/socket_consumer.h>
#include <protocols/errors.h>
-#include <protocols/incremental_indexer.h>
+#include <protocols/incremental_indexer_bytestream.h>
#include <protocols/transport_protocol.h>
namespace transport {
namespace protocol {
void IncrementalIndexer::onContentObject(core::Interest &interest,
- core::ContentObject &content_object) {
+ core::ContentObject &content_object,
+ bool reassembly) {
using namespace interface;
- TRANSPORT_LOGD("Received content %s",
- content_object.getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received content " << content_object.getName();
+
+ assert(reassembly_);
if (TRANSPORT_EXPECT_FALSE(content_object.testRst())) {
final_suffix_ = content_object.getName().getSuffix();
@@ -36,16 +39,22 @@ void IncrementalIndexer::onContentObject(core::Interest &interest,
switch (ret) {
case auth::VerificationPolicy::ACCEPT: {
- reassembly_->reassemble(content_object);
+ if (reassembly) {
+ reassembly_->reassemble(content_object);
+ }
break;
}
+
case auth::VerificationPolicy::UNKNOWN:
case auth::VerificationPolicy::DROP: {
- transport_protocol_->onPacketDropped(interest, content_object);
+ transport_->onPacketDropped(
+ interest, content_object,
+ make_error_code(protocol_error::verification_failed));
break;
}
+
case auth::VerificationPolicy::ABORT: {
- transport_protocol_->onContentReassembled(
+ transport_->onContentReassembled(
make_error_code(protocol_error::session_aborted));
break;
}
diff --git a/libtransport/src/protocols/incremental_indexer_bytestream.h b/libtransport/src/protocols/incremental_indexer_bytestream.h
new file mode 100644
index 000000000..c6a669629
--- /dev/null
+++ b/libtransport/src/protocols/incremental_indexer_bytestream.h
@@ -0,0 +1,119 @@
+/*
+ * 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/errors.h>
+#include <hicn/transport/interfaces/callbacks.h>
+#include <hicn/transport/utils/literals.h>
+#include <implementation/socket_consumer.h>
+#include <protocols/indexer.h>
+#include <protocols/reassembly.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace interface {
+class ConsumerSocket;
+}
+
+namespace protocol {
+
+class Reassembly;
+class TransportProtocol;
+
+class IncrementalIndexer : public Indexer {
+ public:
+ IncrementalIndexer(implementation::ConsumerSocket *icn_socket,
+ TransportProtocol *transport)
+ : Indexer(icn_socket, transport),
+ final_suffix_(Indexer::invalid_index),
+ first_suffix_(0),
+ next_download_suffix_(0),
+ next_reassembly_suffix_(0) {}
+
+ IncrementalIndexer(const IncrementalIndexer &other) = delete;
+
+ IncrementalIndexer(IncrementalIndexer &&other)
+ : Indexer(std::forward<Indexer>(other)),
+ final_suffix_(other.final_suffix_),
+ first_suffix_(other.first_suffix_),
+ next_download_suffix_(other.next_download_suffix_),
+ next_reassembly_suffix_(other.next_reassembly_suffix_) {}
+
+ virtual ~IncrementalIndexer() {}
+
+ virtual void reset() override {
+ final_suffix_ = Indexer::invalid_index;
+ next_download_suffix_ = first_suffix_;
+ next_reassembly_suffix_ = first_suffix_;
+ }
+
+ virtual uint32_t checkNextSuffix() override {
+ return next_download_suffix_ <= final_suffix_ ? next_download_suffix_
+ : Indexer::invalid_index;
+ }
+
+ virtual uint32_t getNextSuffix() override {
+ return next_download_suffix_ <= final_suffix_ ? next_download_suffix_++
+ : Indexer::invalid_index;
+ }
+
+ virtual void setFirstSuffix(uint32_t suffix) override {
+ first_suffix_ = suffix;
+ }
+
+ uint32_t getFirstSuffix() override { return first_suffix_; }
+
+ virtual uint32_t jumpToIndex(uint32_t index) override {
+ next_download_suffix_ = index;
+ return next_download_suffix_;
+ }
+
+ /**
+ * Retrive the next segment to be reassembled.
+ */
+ virtual uint32_t getNextReassemblySegment() override {
+ return next_reassembly_suffix_ <= final_suffix_ ? next_reassembly_suffix_++
+ : Indexer::invalid_index;
+ }
+
+ virtual bool isFinalSuffixDiscovered() override {
+ return final_suffix_ != Indexer::invalid_index;
+ }
+
+ virtual uint32_t getFinalSuffix() override { return final_suffix_; }
+
+ void enableFec(fec::FECType fec_type) override {}
+
+ void disableFec() override {}
+
+ void setNFec(uint32_t n_fec) override {}
+ virtual uint32_t getNFec() override { return 0; }
+
+ virtual void onContentObject(core::Interest &interest,
+ core::ContentObject &content_object,
+ bool reassembly) override;
+
+ protected:
+ uint32_t final_suffix_;
+ uint32_t first_suffix_;
+ uint32_t next_download_suffix_;
+ uint32_t next_reassembly_suffix_;
+};
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/protocols/index_manager_bytestream.cc b/libtransport/src/protocols/index_manager_bytestream.cc
new file mode 100644
index 000000000..c78dc634d
--- /dev/null
+++ b/libtransport/src/protocols/index_manager_bytestream.cc
@@ -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.
+ */
+
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <protocols/index_manager_bytestream.h>
+#include <protocols/manifest_incremental_indexer_bytestream.h>
+#include <protocols/transport_protocol.h>
+
+namespace transport {
+namespace protocol {
+
+IndexManager::IndexManager(implementation::ConsumerSocket *icn_socket,
+ TransportProtocol *transport)
+ : IncrementalIndexer(icn_socket, transport),
+ indexer_(std::make_unique<IncrementalIndexer>(icn_socket, transport)),
+ first_segment_received_(false) {}
+
+void IndexManager::onContentObject(core::Interest &interest,
+ core::ContentObject &content_object,
+ bool reassembly) {
+ if (first_segment_received_) {
+ return indexer_->onContentObject(interest, content_object, reassembly);
+ } else {
+ std::uint32_t segment_number = interest.getName().getSuffix();
+
+ if (segment_number == 0) {
+ // Check if manifest
+ if (content_object.getPayloadType() == core::PayloadType::MANIFEST) {
+ IncrementalIndexer *indexer =
+ static_cast<IncrementalIndexer *>(indexer_.release());
+ indexer_ =
+ std::make_unique<ManifestIncrementalIndexer>(std::move(*indexer));
+ delete indexer;
+ }
+
+ indexer_->onContentObject(interest, content_object);
+ auto it = interest_data_set_.begin();
+ while (it != interest_data_set_.end()) {
+ indexer_->onContentObject(*it->first, *it->second);
+ it = interest_data_set_.erase(it);
+ }
+
+ first_segment_received_ = true;
+ } else {
+ interest_data_set_.emplace(interest.shared_from_this(),
+ content_object.shared_from_this());
+ }
+ }
+}
+
+void IndexManager::reset() {
+ indexer_ = std::make_unique<IncrementalIndexer>(socket_, transport_);
+ indexer_->setReassembly(this->reassembly_);
+ indexer_->reset();
+ first_segment_received_ = false;
+ interest_data_set_.clear();
+}
+
+} // namespace protocol
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/protocols/index_manager_bytestream.h b/libtransport/src/protocols/index_manager_bytestream.h
new file mode 100644
index 000000000..e14c8845b
--- /dev/null
+++ b/libtransport/src/protocols/index_manager_bytestream.h
@@ -0,0 +1,91 @@
+/*
+ * 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 <protocols/incremental_indexer_bytestream.h>
+
+#include <list>
+
+namespace transport {
+
+namespace implementation {
+class ConsumerSocket;
+}
+
+namespace protocol {
+
+class TransportProtocol;
+
+class IndexManager : public IncrementalIndexer {
+ public:
+ IndexManager(implementation::ConsumerSocket *icn_socket,
+ TransportProtocol *transport);
+
+ uint32_t getNextSuffix() override { return indexer_->getNextSuffix(); }
+
+ void setFirstSuffix(uint32_t suffix) override {
+ indexer_->setFirstSuffix(suffix);
+ }
+
+ uint32_t getFirstSuffix() override { return indexer_->getFirstSuffix(); }
+
+ uint32_t getNextReassemblySegment() override {
+ return indexer_->getNextReassemblySegment();
+ }
+
+ bool isFinalSuffixDiscovered() override {
+ return indexer_->isFinalSuffixDiscovered();
+ }
+
+ uint32_t getFinalSuffix() override { return indexer_->getFinalSuffix(); }
+
+ uint32_t jumpToIndex(uint32_t index) override {
+ return indexer_->jumpToIndex(index);
+ }
+
+ void setNFec(uint32_t n_fec) override { return indexer_->setNFec(n_fec); }
+ uint32_t getNFec() override { return indexer_->getNFec(); }
+
+ void enableFec(fec::FECType fec_type) override {
+ return indexer_->enableFec(fec_type);
+ }
+
+ double getFecOverhead() override { return indexer_->getFecOverhead(); }
+
+ double getMaxFecOverhead() override { return indexer_->getMaxFecOverhead(); }
+
+ void disableFec() override { return indexer_->disableFec(); }
+
+ void reset() override;
+
+ void setReassembly(Reassembly *reassembly) override {
+ Indexer::setReassembly(reassembly);
+ indexer_->setReassembly(reassembly);
+ }
+
+ void onContentObject(core::Interest &interest,
+ core::ContentObject &content_object,
+ bool reassembly) override;
+
+ private:
+ std::unique_ptr<Indexer> indexer_;
+ bool first_segment_received_;
+ std::set<std::pair<core::Interest::Ptr, core::ContentObject::Ptr>>
+ interest_data_set_;
+};
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/protocols/indexer.cc b/libtransport/src/protocols/indexer.cc
index 1379a609c..8d4cf04d7 100644
--- a/libtransport/src/protocols/indexer.cc
+++ b/libtransport/src/protocols/indexer.cc
@@ -13,61 +13,29 @@
* limitations under the License.
*/
-#include <hicn/transport/utils/branch_prediction.h>
-#include <protocols/incremental_indexer.h>
+#include <implementation/socket_consumer.h>
#include <protocols/indexer.h>
-#include <protocols/manifest_incremental_indexer.h>
namespace transport {
-namespace protocol {
-IndexManager::IndexManager(implementation::ConsumerSocket *icn_socket,
- TransportProtocol *transport, Reassembly *reassembly)
- : indexer_(std::make_unique<IncrementalIndexer>(icn_socket, transport,
- reassembly)),
- first_segment_received_(false),
- icn_socket_(icn_socket),
- transport_(transport),
- reassembly_(reassembly) {}
+namespace protocol {
-void IndexManager::onContentObject(core::Interest &interest,
- core::ContentObject &content_object) {
- if (first_segment_received_) {
- indexer_->onContentObject(interest, content_object);
- } else {
- std::uint32_t segment_number = interest.getName().getSuffix();
+using namespace interface;
- if (segment_number == 0) {
- // Check if manifest
- if (content_object.getPayloadType() == core::PayloadType::MANIFEST) {
- IncrementalIndexer *indexer =
- static_cast<IncrementalIndexer *>(indexer_.release());
- indexer_ =
- std::make_unique<ManifestIncrementalIndexer>(std::move(*indexer));
- delete indexer;
- }
+const constexpr uint32_t Indexer::invalid_index;
- indexer_->onContentObject(interest, content_object);
- auto it = interest_data_set_.begin();
- while (it != interest_data_set_.end()) {
- indexer_->onContentObject(*it->first, *it->second);
- it = interest_data_set_.erase(it);
- }
+Indexer::Indexer(implementation::ConsumerSocket *socket,
+ TransportProtocol *transport)
+ : socket_(socket), transport_(transport) {
+ setVerifier();
+}
- first_segment_received_ = true;
- } else {
- interest_data_set_.emplace(interest.shared_from_this(),
- content_object.shared_from_this());
- }
+void Indexer::setVerifier() {
+ if (socket_) {
+ socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier_);
}
}
-void IndexManager::reset(std::uint32_t offset) {
- indexer_ = std::make_unique<IncrementalIndexer>(icn_socket_, transport_,
- reassembly_);
- first_segment_received_ = false;
- interest_data_set_.clear();
-}
+} // end namespace protocol
-} // namespace protocol
-} // namespace transport
+} // end namespace transport
diff --git a/libtransport/src/protocols/indexer.h b/libtransport/src/protocols/indexer.h
index 49e22a4cf..7e3a52fb0 100644
--- a/libtransport/src/protocols/indexer.h
+++ b/libtransport/src/protocols/indexer.h
@@ -17,6 +17,7 @@
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
+#include <protocols/fec_utils.h>
#include <set>
@@ -33,66 +34,80 @@ class TransportProtocol;
class Indexer {
public:
+ static const constexpr uint32_t invalid_index =
+ (std::numeric_limits<uint32_t>::max() - 1);
+
+ Indexer(implementation::ConsumerSocket *socket, TransportProtocol *transport);
+
virtual ~Indexer() = default;
/**
- * Retrieve from the manifest the next suffix to retrieve.
+ * Suffix getters
*/
+ virtual uint32_t checkNextSuffix() = 0;
virtual uint32_t getNextSuffix() = 0;
+ virtual uint32_t getNextReassemblySegment() = 0;
+ /**
+ * Set first suffix from where to start.
+ */
virtual void setFirstSuffix(uint32_t suffix) = 0;
+ virtual uint32_t getFirstSuffix() = 0;
/**
- * Retrive the next segment to be reassembled.
+ * Functions to set/enable/disable fec
*/
- virtual uint32_t getNextReassemblySegment() = 0;
+ virtual void setNFec(uint32_t n_fec) = 0;
+ virtual uint32_t getNFec() = 0;
+ virtual void enableFec(fec::FECType fec_type) = 0;
+ virtual void disableFec() = 0;
+ virtual bool isFec(uint32_t index) { return false; }
+ virtual double getFecOverhead() { return 0.0; }
+ virtual double getMaxFecOverhead() { return 0.0; }
+ /**
+ * Final suffix helpers.
+ */
virtual bool isFinalSuffixDiscovered() = 0;
-
virtual uint32_t getFinalSuffix() = 0;
- virtual void reset(std::uint32_t offset = 0) = 0;
-
- virtual void onContentObject(core::Interest &interest,
- core::ContentObject &content_object) = 0;
-};
-
-class IndexManager : Indexer {
- public:
- static constexpr uint32_t invalid_index = ~0;
-
- IndexManager(implementation::ConsumerSocket *icn_socket,
- TransportProtocol *transport, Reassembly *reassembly);
-
- uint32_t getNextSuffix() override { return indexer_->getNextSuffix(); }
-
- void setFirstSuffix(uint32_t suffix) override {
- indexer_->setFirstSuffix(suffix);
- }
-
- uint32_t getNextReassemblySegment() override {
- return indexer_->getNextReassemblySegment();
+ /**
+ * Set reassembly protocol
+ */
+ virtual void setReassembly(Reassembly *reassembly) {
+ reassembly_ = reassembly;
}
- bool isFinalSuffixDiscovered() override {
- return indexer_->isFinalSuffixDiscovered();
- }
+ /**
+ * Set verifier using socket
+ */
+ virtual void setVerifier();
- uint32_t getFinalSuffix() override { return indexer_->getFinalSuffix(); }
+ /**
+ * Jump to suffix. This may be useful if, for any protocol dependent
+ * mechanism, we need to suddenly change current suffix. This does not modify
+ * the way suffixes re incremented/decremented (that's part of the
+ * implementation).
+ */
+ virtual uint32_t jumpToIndex(uint32_t index) = 0;
- void reset(std::uint32_t offset = 0) override;
+ /**
+ * Reset the indexer.
+ */
+ virtual void reset() = 0;
- void onContentObject(core::Interest &interest,
- core::ContentObject &content_object) override;
+ /**
+ * Process incoming content objects.
+ */
+ virtual void onContentObject(core::Interest &interest,
+ core::ContentObject &content_object,
+ bool reassembly = true) = 0;
- private:
- std::unique_ptr<Indexer> indexer_;
- bool first_segment_received_;
- std::set<std::pair<core::Interest::Ptr, core::ContentObject::Ptr>>
- interest_data_set_;
- implementation::ConsumerSocket *icn_socket_;
+ protected:
+ implementation::ConsumerSocket *socket_;
TransportProtocol *transport_;
Reassembly *reassembly_;
+ std::shared_ptr<auth::Verifier> verifier_;
};
} // end namespace protocol
diff --git a/libtransport/src/protocols/manifest_incremental_indexer.cc b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
index a6312ca90..168aa57af 100644
--- a/libtransport/src/protocols/manifest_incremental_indexer.cc
+++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
@@ -15,7 +15,7 @@
#include <implementation/socket_consumer.h>
#include <protocols/errors.h>
-#include <protocols/manifest_incremental_indexer.h>
+#include <protocols/manifest_incremental_indexer_bytestream.h>
#include <protocols/transport_protocol.h>
#include <cmath>
@@ -28,26 +28,26 @@ namespace protocol {
using namespace interface;
ManifestIncrementalIndexer::ManifestIncrementalIndexer(
- implementation::ConsumerSocket *icn_socket, TransportProtocol *transport,
- Reassembly *reassembly)
- : IncrementalIndexer(icn_socket, transport, reassembly),
+ implementation::ConsumerSocket *icn_socket, TransportProtocol *transport)
+ : IncrementalIndexer(icn_socket, transport),
suffix_strategy_(utils::SuffixStrategyFactory::getSuffixStrategy(
NextSegmentCalculationStrategy::INCREMENTAL, next_download_suffix_,
0)) {}
void ManifestIncrementalIndexer::onContentObject(
- core::Interest &interest, core::ContentObject &content_object) {
+ core::Interest &interest, core::ContentObject &content_object,
+ bool reassembly) {
switch (content_object.getPayloadType()) {
case PayloadType::DATA: {
- TRANSPORT_LOGD("Received content %s",
- content_object.getName().toString().c_str());
- onUntrustedContentObject(interest, content_object);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received content " << content_object.getName();
+ onUntrustedContentObject(interest, content_object, reassembly);
break;
}
case PayloadType::MANIFEST: {
- TRANSPORT_LOGD("Received manifest %s",
- content_object.getName().toString().c_str());
- onUntrustedManifest(interest, content_object);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received manifest " << content_object.getName();
+ onUntrustedManifest(interest, content_object, reassembly);
break;
}
default: {
@@ -57,7 +57,8 @@ void ManifestIncrementalIndexer::onContentObject(
}
void ManifestIncrementalIndexer::onUntrustedManifest(
- core::Interest &interest, core::ContentObject &content_object) {
+ core::Interest &interest, core::ContentObject &content_object,
+ bool reassembly) {
auto manifest =
std::make_unique<ContentObjectManifest>(std::move(content_object));
@@ -66,16 +67,17 @@ void ManifestIncrementalIndexer::onUntrustedManifest(
manifest->decode();
if (policy != auth::VerificationPolicy::ACCEPT) {
- transport_protocol_->onContentReassembled(
+ transport_->onContentReassembled(
make_error_code(protocol_error::session_aborted));
return;
}
- processTrustedManifest(interest, std::move(manifest));
+ processTrustedManifest(interest, std::move(manifest), reassembly);
}
void ManifestIncrementalIndexer::processTrustedManifest(
- core::Interest &interest, std::unique_ptr<ContentObjectManifest> manifest) {
+ core::Interest &interest, std::unique_ptr<ContentObjectManifest> manifest,
+ bool reassembly) {
if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() !=
core::ManifestVersion::VERSION_1)) {
throw errors::RuntimeException("Received manifest with unknown version.");
@@ -89,7 +91,7 @@ void ManifestIncrementalIndexer::processTrustedManifest(
std::vector<auth::PacketPtr> packets;
// Convert the received manifest to a map of packet suffixes to hashes
- std::unordered_map<auth::Suffix, auth::HashEntry> current_manifest =
+ auth::Verifier::SuffixMap current_manifest =
core::ContentObjectManifest::getSuffixMap(manifest.get());
// Update 'suffix_map_' with new hashes from the received manifest and
@@ -102,26 +104,31 @@ void ManifestIncrementalIndexer::processTrustedManifest(
continue;
}
- packets.push_back(unverified_segments_[it->first].second.get());
+ packets.push_back(std::get<1>(unverified_segments_[it->first]).get());
it++;
}
// Verify unverified segments using the received manifest
- std::vector<auth::VerificationPolicy> policies =
+ auth::Verifier::PolicyMap policies =
verifier_->verifyPackets(packets, current_manifest);
for (unsigned int i = 0; i < packets.size(); ++i) {
auth::Suffix suffix = packets[i]->getName().getSuffix();
- if (policies[i] != auth::VerificationPolicy::UNKNOWN) {
- unverified_segments_.erase(suffix);
+ auto it = unverified_segments_.find(suffix);
+
+ if (policies[suffix] != auth::VerificationPolicy::UNKNOWN) {
+ unverified_segments_.erase(it);
+ continue;
}
- applyPolicy(*unverified_segments_[suffix].first,
- *unverified_segments_[suffix].second, policies[i]);
+ applyPolicy(*std::get<0>(it->second), *std::get<1>(it->second),
+ std::get<2>(it->second), policies[suffix]);
}
- reassembly_->reassemble(std::move(manifest));
+ if (reassembly) {
+ reassembly_->reassemble(std::move(manifest));
+ }
break;
}
case core::ManifestType::FLIC_MANIFEST: {
@@ -134,15 +141,16 @@ void ManifestIncrementalIndexer::processTrustedManifest(
}
void ManifestIncrementalIndexer::onUntrustedContentObject(
- Interest &interest, ContentObject &content_object) {
+ Interest &interest, ContentObject &content_object, bool reassembly) {
auth::Suffix suffix = content_object.getName().getSuffix();
auth::VerificationPolicy policy =
verifier_->verifyPackets(&content_object, suffix_map_);
switch (policy) {
case auth::VerificationPolicy::UNKNOWN: {
- unverified_segments_[suffix] = std::make_pair(
- interest.shared_from_this(), content_object.shared_from_this());
+ unverified_segments_[suffix] =
+ std::make_tuple(interest.shared_from_this(),
+ content_object.shared_from_this(), reassembly);
break;
}
default: {
@@ -151,32 +159,43 @@ void ManifestIncrementalIndexer::onUntrustedContentObject(
}
}
- applyPolicy(interest, content_object, policy);
+ applyPolicy(interest, content_object, reassembly, policy);
}
void ManifestIncrementalIndexer::applyPolicy(
core::Interest &interest, core::ContentObject &content_object,
- auth::VerificationPolicy policy) {
+ bool reassembly, auth::VerificationPolicy policy) {
+ assert(reassembly_);
switch (policy) {
case auth::VerificationPolicy::ACCEPT: {
- reassembly_->reassemble(content_object);
+ if (reassembly && !reassembly_->reassembleUnverified()) {
+ reassembly_->reassemble(content_object);
+ }
break;
}
case auth::VerificationPolicy::DROP: {
- transport_protocol_->onPacketDropped(interest, content_object);
+ transport_->onPacketDropped(
+ interest, content_object,
+ make_error_code(protocol_error::verification_failed));
break;
}
case auth::VerificationPolicy::ABORT: {
- transport_protocol_->onContentReassembled(
+ transport_->onContentReassembled(
make_error_code(protocol_error::session_aborted));
break;
}
- default: {
- break;
+ case auth::VerificationPolicy::UNKNOWN: {
+ if (reassembly && reassembly_->reassembleUnverified()) {
+ reassembly_->reassemble(content_object);
+ }
}
}
}
+uint32_t ManifestIncrementalIndexer::checkNextSuffix() {
+ return suffix_strategy_->getNextSuffix();
+}
+
uint32_t ManifestIncrementalIndexer::getNextSuffix() {
auto ret = suffix_strategy_->getNextSuffix();
@@ -186,7 +205,7 @@ uint32_t ManifestIncrementalIndexer::getNextSuffix() {
return ret;
}
- return IndexManager::invalid_index;
+ return Indexer::invalid_index;
}
uint32_t ManifestIncrementalIndexer::getFinalSuffix() {
@@ -199,7 +218,7 @@ bool ManifestIncrementalIndexer::isFinalSuffixDiscovered() {
uint32_t ManifestIncrementalIndexer::getNextReassemblySegment() {
if (suffix_queue_.empty()) {
- return IndexManager::invalid_index;
+ return Indexer::invalid_index;
}
auto ret = suffix_queue_.front();
@@ -207,13 +226,13 @@ uint32_t ManifestIncrementalIndexer::getNextReassemblySegment() {
return ret;
}
-void ManifestIncrementalIndexer::reset(std::uint32_t offset) {
- IncrementalIndexer::reset(offset);
+void ManifestIncrementalIndexer::reset() {
+ IncrementalIndexer::reset();
suffix_map_.clear();
unverified_segments_.clear();
SuffixQueue empty;
std::swap(suffix_queue_, empty);
- suffix_strategy_->reset(offset);
+ suffix_strategy_->reset(first_suffix_);
}
} // namespace protocol
diff --git a/libtransport/src/protocols/manifest_incremental_indexer.h b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
index 1bb76eb87..d8cf5892f 100644
--- a/libtransport/src/protocols/manifest_incremental_indexer.h
+++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
@@ -17,7 +17,7 @@
#include <hicn/transport/auth/common.h>
#include <implementation/socket.h>
-#include <protocols/incremental_indexer.h>
+#include <protocols/incremental_indexer_bytestream.h>
#include <utils/suffix_strategy.h>
#include <list>
@@ -31,11 +31,10 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
public:
using SuffixQueue = std::queue<uint32_t>;
using InterestContentPair =
- std::pair<core::Interest::Ptr, core::ContentObject::Ptr>;
+ std::tuple<core::Interest::Ptr, core::ContentObject::Ptr, bool>;
ManifestIncrementalIndexer(implementation::ConsumerSocket *icn_socket,
- TransportProtocol *transport,
- Reassembly *reassembly);
+ TransportProtocol *transport);
ManifestIncrementalIndexer(IncrementalIndexer &&indexer)
: IncrementalIndexer(std::move(indexer)),
@@ -49,10 +48,13 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
virtual ~ManifestIncrementalIndexer() = default;
- void reset(std::uint32_t offset = 0) override;
+ void reset() override;
void onContentObject(core::Interest &interest,
- core::ContentObject &content_object) override;
+ core::ContentObject &content_object,
+ bool reassembly) override;
+
+ uint32_t checkNextSuffix() override;
uint32_t getNextSuffix() override;
@@ -67,18 +69,21 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
SuffixQueue suffix_queue_;
// Hash verification
- std::unordered_map<auth::Suffix, auth::HashEntry> suffix_map_;
+ auth::Verifier::SuffixMap suffix_map_;
std::unordered_map<auth::Suffix, InterestContentPair> unverified_segments_;
private:
void onUntrustedManifest(core::Interest &interest,
- core::ContentObject &content_object);
+ core::ContentObject &content_object,
+ bool reassembly);
void processTrustedManifest(core::Interest &interest,
- std::unique_ptr<ContentObjectManifest> manifest);
+ std::unique_ptr<ContentObjectManifest> manifest,
+ bool reassembly);
void onUntrustedContentObject(core::Interest &interest,
- core::ContentObject &content_object);
+ core::ContentObject &content_object,
+ bool reassembly);
void applyPolicy(core::Interest &interest,
- core::ContentObject &content_object,
+ core::ContentObject &content_object, bool reassembly,
auth::VerificationPolicy policy);
};
diff --git a/libtransport/src/protocols/packet_manager.h b/libtransport/src/protocols/packet_manager.h
deleted file mode 100644
index a552607ea..000000000
--- a/libtransport/src/protocols/packet_manager.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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/object_pool.h>
-
-namespace transport {
-
-namespace protocol {
-
-using namespace core;
-
-template <typename PacketType, std::size_t packet_pool_size = 4096>
-class PacketManager {
- static_assert(std::is_base_of<Packet, PacketType>::value,
- "The packet manager support just Interest and Data.");
-
- public:
- PacketManager(std::size_t size = packet_pool_size) : size_(0) {
- // Create pool of interests
- increasePoolSize(size);
- }
-
- TRANSPORT_ALWAYS_INLINE void increasePoolSize(std::size_t size) {
- for (std::size_t i = 0; i < size; i++) {
- interest_pool_.add(new PacketType());
- }
-
- size_ += size;
- }
-
- TRANSPORT_ALWAYS_INLINE typename PacketType::Ptr getPacket() {
- auto result = interest_pool_.get();
-
- while (TRANSPORT_EXPECT_FALSE(!result.first)) {
- // Add packets to the pool
- increasePoolSize(size_);
- result = interest_pool_.get();
- }
-
- result.second->resetPayload();
- return std::move(result.second);
- }
-
- private:
- utils::ObjectPool<PacketType> interest_pool_;
- std::size_t size_;
-};
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/prod_protocol_bytestream.cc b/libtransport/src/protocols/prod_protocol_bytestream.cc
index 6bd989fe4..f659cb37c 100644
--- a/libtransport/src/protocols/prod_protocol_bytestream.cc
+++ b/libtransport/src/protocols/prod_protocol_bytestream.cc
@@ -87,11 +87,6 @@ uint32_t ByteStreamProductionProtocol::produceStream(
auth::CryptoHashType hash_algo;
socket_->getSocketOption(GeneralTransportOptions::HASH_ALGORITHM, hash_algo);
- // Use manifest
- bool making_manifest;
- socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
- making_manifest);
-
// Suffix calculation strategy
core::NextSegmentCalculationStrategy _suffix_strategy;
socket_->getSocketOption(GeneralTransportOptions::SUFFIX_STRATEGY,
@@ -99,9 +94,6 @@ uint32_t ByteStreamProductionProtocol::produceStream(
auto suffix_strategy = utils::SuffixStrategyFactory::getSuffixStrategy(
_suffix_strategy, start_offset);
- std::shared_ptr<auth::Signer> signer;
- socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer);
-
auto buffer_size = buffer->length();
int bytes_segmented = 0;
std::size_t header_size;
@@ -115,8 +107,8 @@ uint32_t ByteStreamProductionProtocol::produceStream(
bool is_last_manifest = false;
// TODO Manifest may still be used for indexing
- if (making_manifest && !signer) {
- TRANSPORT_LOGE("Making manifests without setting producer identity.");
+ if (making_manifest_ && !signer_) {
+ LOG(FATAL) << "Making manifests without setting producer identity.";
}
core::Packet::Format hf_format = core::Packet::Format::HF_UNSPEC;
@@ -134,13 +126,13 @@ uint32_t ByteStreamProductionProtocol::produceStream(
}
format = hf_format;
- if (making_manifest) {
+ if (making_manifest_) {
manifest_header_size = core::Packet::getHeaderSizeFromFormat(
- signer ? hf_format_ah : hf_format,
- signer ? signer->getSignatureSize() : 0);
- } else if (signer) {
+ signer_ ? hf_format_ah : hf_format,
+ signer_ ? signer_->getSignatureFieldSize() : 0);
+ } else if (signer_) {
format = hf_format_ah;
- signature_length = signer->getSignatureSize();
+ signature_length = signer_->getSignatureFieldSize();
}
header_size = core::Packet::getHeaderSizeFromFormat(format, signature_length);
@@ -152,7 +144,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
}
// TODO allocate space for all the headers
- if (making_manifest) {
+ if (making_manifest_) {
uint32_t segment_in_manifest = static_cast<uint32_t>(
std::floor(double(data_packet_size - manifest_header_size -
ContentObjectManifest::getManifestHeaderSize()) /
@@ -166,7 +158,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
name.setSuffix(suffix_strategy->getNextManifestSuffix()),
core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
hash_algo, is_last_manifest, name, _suffix_strategy,
- signer ? signer->getSignatureSize() : 0));
+ signer_ ? signer_->getSignatureFieldSize() : 0));
manifest->setLifetime(content_object_expiry_time);
if (is_last) {
@@ -178,27 +170,26 @@ uint32_t ByteStreamProductionProtocol::produceStream(
for (unsigned int packaged_segments = 0;
packaged_segments < number_of_segments; packaged_segments++) {
- if (making_manifest) {
+ if (making_manifest_) {
if (manifest->estimateManifestSize(2) >
data_packet_size - manifest_header_size) {
manifest->encode();
// If identity set, sign manifest
- if (signer) {
- signer->signPacket(manifest.get());
+ if (signer_) {
+ signer_->signPacket(manifest.get());
}
// Send the current manifest
passContentObjectToCallbacks(manifest);
- TRANSPORT_LOGD("Send manifest %s",
- manifest->getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
// Send content objects stored in the queue
while (!content_queue_.empty()) {
passContentObjectToCallbacks(content_queue_.front());
- TRANSPORT_LOGD("Send content %s",
- content_queue_.front()->getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Send content " << content_queue_.front()->getName();
content_queue_.pop();
}
@@ -209,7 +200,8 @@ uint32_t ByteStreamProductionProtocol::produceStream(
name.setSuffix(suffix_strategy->getNextManifestSuffix()),
core::ManifestVersion::VERSION_1,
core::ManifestType::INLINE_MANIFEST, hash_algo, is_last_manifest,
- name, _suffix_strategy, signer ? signer->getSignatureSize() : 0));
+ name, _suffix_strategy,
+ signer_ ? signer_->getSignatureFieldSize() : 0));
manifest->setLifetime(content_object_expiry_time);
manifest->setFinalBlockNumber(
@@ -221,7 +213,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
auto content_suffix = suffix_strategy->getNextContentSuffix();
auto content_object = std::make_shared<ContentObject>(
name.setSuffix(content_suffix), format,
- signer && !making_manifest ? signer->getSignatureSize() : 0);
+ signer_ && !making_manifest_ ? signer_->getSignatureFieldSize() : 0);
content_object->setLifetime(content_object_expiry_time);
auto b = buffer->cloneOne();
@@ -232,7 +224,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
b->append(buffer_size - bytes_segmented);
bytes_segmented += (int)(buffer_size - bytes_segmented);
- if (is_last && making_manifest) {
+ if (is_last && making_manifest_) {
is_last_manifest = true;
} else if (is_last) {
content_object->setRst();
@@ -245,39 +237,39 @@ uint32_t ByteStreamProductionProtocol::produceStream(
content_object->appendPayload(std::move(b));
- if (making_manifest) {
+ if (making_manifest_) {
using namespace std::chrono_literals;
auth::CryptoHash hash = content_object->computeDigest(hash_algo);
manifest->addSuffixHash(content_suffix, hash);
content_queue_.push(content_object);
} else {
- if (signer) {
- signer->signPacket(content_object.get());
+ if (signer_) {
+ signer_->signPacket(content_object.get());
}
passContentObjectToCallbacks(content_object);
- TRANSPORT_LOGD("Send content %s",
- content_object->getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Send content " << content_object->getName();
}
}
- if (making_manifest) {
+ if (making_manifest_) {
if (is_last_manifest) {
manifest->setFinalManifest(is_last_manifest);
}
manifest->encode();
- if (signer) {
- signer->signPacket(manifest.get());
+ if (signer_) {
+ signer_->signPacket(manifest.get());
}
passContentObjectToCallbacks(manifest);
- TRANSPORT_LOGD("Send manifest %s", manifest->getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
while (!content_queue_.empty()) {
passContentObjectToCallbacks(content_queue_.front());
- TRANSPORT_LOGD("Send content %s",
- content_queue_.front()->getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Send content " << content_queue_.front()->getName();
content_queue_.pop();
}
}
@@ -356,14 +348,14 @@ void ByteStreamProductionProtocol::passContentObjectToCallbacks(
}
void ByteStreamProductionProtocol::onInterest(Interest &interest) {
- TRANSPORT_LOGD("Received interest for %s",
- interest.getName().toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received interest for " << interest.getName();
if (*on_interest_input_) {
on_interest_input_->operator()(*socket_->getInterface(), interest);
}
const std::shared_ptr<ContentObject> content_object =
- output_buffer_.find(interest);
+ output_buffer_.find(interest.getName());
if (content_object) {
if (*on_interest_satisfied_output_buffer_) {
diff --git a/libtransport/src/protocols/prod_protocol_rtc.cc b/libtransport/src/protocols/prod_protocol_rtc.cc
index 049752876..cdc882d81 100644
--- a/libtransport/src/protocols/prod_protocol_rtc.cc
+++ b/libtransport/src/protocols/prod_protocol_rtc.cc
@@ -25,15 +25,19 @@
namespace transport {
namespace protocol {
+using Format = core::Packet::Format;
+
RTCProductionProtocol::RTCProductionProtocol(
implementation::ProducerSocket *icn_socket)
: ProductionProtocol(icn_socket),
current_seg_(1),
produced_bytes_(0),
produced_packets_(0),
+ produced_fec_packets_(0),
max_packet_production_(1),
bytes_production_rate_(0),
packets_production_rate_(0),
+ fec_packets_production_rate_(0),
last_round_(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count()),
@@ -43,11 +47,17 @@ RTCProductionProtocol::RTCProductionProtocol(
on_consumer_in_sync_(nullptr) {
srand((unsigned int)time(NULL));
prod_label_ = rand() % 256;
+ cache_label_ = (prod_label_ + 1) % 256;
interests_queue_timer_ =
std::make_unique<asio::steady_timer>(portal_->getIoService());
round_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
setOutputBufferSize(10000);
scheduleRoundTimer();
+
+ // FEC
+ using namespace std::placeholders;
+ enableFEC(std::bind(&RTCProductionProtocol::onFecPackets, this, _1),
+ std::bind(&RTCProductionProtocol::getBuffer, this, _1));
}
RTCProductionProtocol::~RTCProductionProtocol() {}
@@ -61,10 +71,19 @@ void RTCProductionProtocol::registerNamespaceWithNetwork(
switch (family) {
case AF_INET6:
- header_size_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET6_TCP);
+ data_header_size_ =
+ signer_ && !making_manifest_
+ ? (uint32_t)Packet::getHeaderSizeFromFormat(
+ HF_INET6_TCP_AH, signer_->getSignatureFieldSize())
+ : (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET6_TCP);
+ ;
break;
case AF_INET:
- header_size_ = (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET_TCP);
+ data_header_size_ =
+ signer_ && !making_manifest_
+ ? (uint32_t)Packet::getHeaderSizeFromFormat(
+ HF_INET_TCP_AH, signer_->getSignatureFieldSize())
+ : (uint32_t)Packet::getHeaderSizeFromFormat(HF_INET_TCP);
break;
default:
throw errors::RuntimeException("Unknown name format.");
@@ -90,16 +109,19 @@ void RTCProductionProtocol::updateStats() {
uint32_t prev_packets_production_rate = packets_production_rate_;
- bytes_production_rate_ = (uint32_t)ceil((double)produced_bytes_ * per_second);
- packets_production_rate_ = (uint32_t)ceil((double)produced_packets_ * per_second);
+ bytes_production_rate_ = ceil((double)produced_bytes_ * per_second);
+ packets_production_rate_ = ceil((double)produced_packets_ * per_second);
+ fec_packets_production_rate_ =
+ ceil((double)produced_fec_packets_ * per_second);
- TRANSPORT_LOGD("Updating production rate: produced_bytes_ = %u bps = %u",
- produced_bytes_, bytes_production_rate_);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Updating production rate: produced_bytes_ = " << produced_bytes_
+ << " bps = " << bytes_production_rate_;
// update the production rate as soon as it increases by 10% with respect to
// the last round
max_packet_production_ =
- produced_packets_ + (uint32_t)ceil((double)produced_packets_ * 0.1);
+ produced_packets_ + ceil((double)produced_packets_ * 0.1);
if (max_packet_production_ < rtc::WIN_MIN)
max_packet_production_ = rtc::WIN_MIN;
@@ -117,6 +139,7 @@ void RTCProductionProtocol::updateStats() {
produced_bytes_ = 0;
produced_packets_ = 0;
+ produced_fec_packets_ = 0;
last_round_ = now;
scheduleRoundTimer();
}
@@ -147,32 +170,34 @@ uint32_t RTCProductionProtocol::produceDatagram(
socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE,
data_packet_size);
- if (TRANSPORT_EXPECT_FALSE((buffer_size + header_size_ +
+ if (TRANSPORT_EXPECT_FALSE((buffer_size + data_header_size_ +
rtc::DATA_HEADER_SIZE) > data_packet_size)) {
return 0;
}
auto content_object =
- core::PacketManager<>::getInstance().getPacket<ContentObject>();
+ core::PacketManager<>::getInstance().getPacket<ContentObject>(
+ signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
+ signer_ ? signer_->getSignatureFieldSize() : 0);
// add rtc header to the payload
struct rtc::data_packet_t header;
content_object->appendPayload((const uint8_t *)&header,
rtc::DATA_HEADER_SIZE);
content_object->appendPayload(buffer->data(), buffer->length());
- std::shared_ptr<ContentObject> co = std::move(content_object);
-
// schedule actual sending on internal thread
- portal_->getIoService().dispatch(
- [this, content_object{std::move(co)}, content_name]() mutable {
- produceInternal(std::move(content_object), content_name);
- });
+ portal_->getIoService().dispatch([this,
+ content_object{std::move(content_object)},
+ content_name]() mutable {
+ produceInternal(std::move(content_object), content_name);
+ });
return 1;
}
void RTCProductionProtocol::produceInternal(
- std::shared_ptr<ContentObject> &&content_object, const Name &content_name) {
+ std::shared_ptr<ContentObject> &&content_object, const Name &content_name,
+ bool fec) {
// set rtc header
struct rtc::data_packet_t *data_pkt =
(struct rtc::data_packet_t *)content_object->getPayload()->data();
@@ -188,10 +213,19 @@ void RTCProductionProtocol::produceInternal(
content_object->setLifetime(500); // XXX this should be set by the APP
content_object->setPathLabel(prod_label_);
+ // sign packet
+ if (signer_) {
+ signer_->signPacket(content_object.get());
+ }
+
// update stats
- produced_bytes_ += (uint32_t)(
- content_object->headerSize() + content_object->payloadSize());
- produced_packets_++;
+ if (!fec) {
+ produced_bytes_ +=
+ content_object->headerSize() + content_object->payloadSize();
+ produced_packets_++;
+ } else {
+ produced_fec_packets_++;
+ }
if (produced_packets_ >= max_packet_production_) {
// in this case all the pending interests may be used to accomodate the
@@ -201,7 +235,14 @@ void RTCProductionProtocol::produceInternal(
updateStats();
}
- TRANSPORT_LOGD("Sending content object: %s", n.toString().c_str());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Sending content object: " << n << ", is fec: " << fec;
+
+ // pass packet to FEC encoder
+ if (fec_encoder_ && !fec) {
+ fec_encoder_->onPacketProduced(
+ *content_object, content_object->headerSize() + rtc::DATA_HEADER_SIZE);
+ }
output_buffer_.insert(content_object);
@@ -210,7 +251,10 @@ void RTCProductionProtocol::produceInternal(
*content_object);
}
- portal_->sendContentObject(*content_object);
+ auto seq_it = seqs_map_.find(current_seg_);
+ if (seq_it != seqs_map_.end()) {
+ portal_->sendContentObject(*content_object);
+ }
if (*on_content_object_output_) {
on_content_object_output_->operator()(*socket_->getInterface(),
@@ -220,58 +264,84 @@ void RTCProductionProtocol::produceInternal(
// remove interests from the interest cache if it exists
removeFromInterestQueue(current_seg_);
+ // Update current segment
current_seg_ = (current_seg_ + 1) % rtc::MIN_PROBE_SEQ;
+
+ // Publish FEC packets if available
+ if (fec_encoder_ && !fec) {
+ while (!fec && pending_fec_packets_.size()) {
+ auto &co = pending_fec_packets_.front();
+ produceInternal(std::move(co), flow_name_, true);
+ pending_fec_packets_.pop();
+ }
+ }
}
void RTCProductionProtocol::onInterest(Interest &interest) {
- uint32_t interest_seg = interest.getName().getSuffix();
- uint32_t lifetime = interest.getLifetime();
+ if (*on_interest_input_) {
+ on_interest_input_->operator()(*socket_->getInterface(), interest);
+ }
+
+ auto suffix = interest.firstSuffix();
+ // numberOfSuffixes returns only the prefixes in the payalod
+ // we add + 1 to count anche the seq in the name
+ auto n_suffixes = interest.numberOfSuffixes() + 1;
+ Name name = interest.getName();
+ bool prev_consumer_state = consumer_in_sync_;
+
+ for (uint32_t i = 0; i < n_suffixes; i++) {
+ if (i > 0) {
+ name.setSuffix(*(suffix + (i - 1)));
+ }
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received interest " << name;
+ const std::shared_ptr<ContentObject> content_object =
+ output_buffer_.find(name);
+
+ if (content_object) {
+ if (*on_interest_satisfied_output_buffer_) {
+ on_interest_satisfied_output_buffer_->operator()(
+ *socket_->getInterface(), interest);
+ }
+
+ if (*on_content_object_output_) {
+ on_content_object_output_->operator()(*socket_->getInterface(),
+ *content_object);
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Send content %u (onInterest) " << content_object->getName();
+ content_object->setPathLabel(cache_label_);
+ portal_->sendContentObject(*content_object);
+ } else {
+ if (*on_interest_process_) {
+ on_interest_process_->operator()(*socket_->getInterface(), interest);
+ }
+ processInterest(name.getSuffix(), interest.getLifetime());
+ }
+ }
+
+ if (prev_consumer_state != consumer_in_sync_ && consumer_in_sync_)
+ on_consumer_in_sync_(*socket_->getInterface(), interest);
+}
+
+void RTCProductionProtocol::processInterest(uint32_t interest_seg,
+ uint32_t lifetime) {
if (interest_seg == 0) {
// first packet from the consumer, reset sync state
consumer_in_sync_ = false;
}
- if (*on_interest_input_) {
- on_interest_input_->operator()(*socket_->getInterface(), interest);
- }
-
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
if (interest_seg > rtc::MIN_PROBE_SEQ) {
- TRANSPORT_LOGD("received probe %u", interest_seg);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received probe " << interest_seg;
sendNack(interest_seg);
return;
}
- TRANSPORT_LOGD("received interest %u", interest_seg);
-
- const std::shared_ptr<ContentObject> content_object =
- output_buffer_.find(interest);
-
- if (content_object) {
- if (*on_interest_satisfied_output_buffer_) {
- on_interest_satisfied_output_buffer_->operator()(*socket_->getInterface(),
- interest);
- }
-
- if (*on_content_object_output_) {
- on_content_object_output_->operator()(*socket_->getInterface(),
- *content_object);
- }
-
- TRANSPORT_LOGD("Send content %u (onInterest)",
- content_object->getName().getSuffix());
- portal_->sendContentObject(*content_object);
- return;
- } else {
- if (*on_interest_process_) {
- on_interest_process_->operator()(*socket_->getInterface(), interest);
- }
- }
-
// if the production rate 0 use delayed nacks
if (allow_delayed_nacks_ && interest_seg >= current_seg_) {
uint64_t next_timer = ~0;
@@ -310,7 +380,8 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
(double)((double)((double)lifetime *
rtc::INTEREST_LIFETIME_REDUCTION_FACTOR /
rtc::MILLI_IN_A_SEC) *
- (double)packets_production_rate_));
+ (double)(packets_production_rate_ +
+ fec_packets_production_rate_)));
if (interest_seg < current_seg_ || interest_seg > (max_gap + current_seg_)) {
sendNack(interest_seg);
@@ -318,14 +389,14 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
if (!consumer_in_sync_ && on_consumer_in_sync_) {
// we consider the remote consumer to be in sync as soon as it covers 70%
// of the production window with interests
- uint32_t perc = (uint32_t)ceil((double)max_gap * 0.7);
+ uint32_t perc = ceil((double)max_gap * 0.7);
if (interest_seg > (perc + current_seg_)) {
consumer_in_sync_ = true;
- on_consumer_in_sync_(*socket_->getInterface(), interest);
+ // on_consumer_in_sync_(*socket_->getInterface(), interest);
}
}
- uint64_t expiration =(uint32_t)(
- now + floor((double)lifetime * rtc::INTEREST_LIFETIME_REDUCTION_FACTOR));
+ uint64_t expiration =
+ now + floor((double)lifetime * rtc::INTEREST_LIFETIME_REDUCTION_FACTOR);
addToInterestQueue(interest_seg, expiration);
}
}
@@ -377,7 +448,7 @@ void RTCProductionProtocol::sendNacksForPendingInterests() {
uint32_t packet_gap = 100000; // set it to a high value (100sec)
if (packets_production_rate_ != 0)
- packet_gap = (uint32_t)ceil(rtc::MILLI_IN_A_SEC / (double)packets_production_rate_);
+ packet_gap = ceil(rtc::MILLI_IN_A_SEC / (double)packets_production_rate_);
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
@@ -441,7 +512,9 @@ void RTCProductionProtocol::interestQueueTimer() {
}
void RTCProductionProtocol::sendNack(uint32_t sequence) {
- auto nack = core::PacketManager<>::getInstance().getPacket<ContentObject>();
+ auto nack = core::PacketManager<>::getInstance().getPacket<ContentObject>(
+ signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
+ signer_ ? signer_->getSignatureFieldSize() : 0);
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
@@ -460,6 +533,10 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) {
nack->setLifetime(0);
nack->setPathLabel(prod_label_);
+ if (signer_) {
+ signer_->signPacket(nack.get());
+ }
+
if (!consumer_in_sync_ && on_consumer_in_sync_ &&
sequence < rtc::MIN_PROBE_SEQ && sequence > next_packet) {
consumer_in_sync_ = true;
@@ -472,10 +549,39 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) {
on_content_object_output_->operator()(*socket_->getInterface(), *nack);
}
- TRANSPORT_LOGD("Send nack %u", sequence);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send nack " << sequence;
portal_->sendContentObject(*nack);
}
+void RTCProductionProtocol::onFecPackets(
+ std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Produced " << packets.size() << " FEC packets";
+ for (auto &packet : packets) {
+ auto content_object =
+ std::static_pointer_cast<ContentObject>(packet.second);
+ content_object->prepend(content_object->headerSize() +
+ rtc::DATA_HEADER_SIZE);
+ pending_fec_packets_.push(std::move(content_object));
+ }
+}
+
+fec::buffer RTCProductionProtocol::getBuffer(std::size_t size) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Asked buffer for FEC symbol of size " << size;
+ auto ret = core::PacketManager<>::getInstance().getPacket<ContentObject>(
+ signer_ ? Format::HF_INET6_TCP_AH : Format::HF_INET6_TCP,
+ signer_ ? signer_->getSignatureFieldSize() : 0);
+ ret->updateLength(rtc::DATA_HEADER_SIZE + size);
+ ret->append(rtc::DATA_HEADER_SIZE + size);
+ ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Responding with buffer of length " << ret->length();
+ assert(ret->length() >= size);
+
+ return ret;
+}
+
} // namespace protocol
} // end namespace transport
diff --git a/libtransport/src/protocols/prod_protocol_rtc.h b/libtransport/src/protocols/prod_protocol_rtc.h
index f3584f74a..96ad5673d 100644
--- a/libtransport/src/protocols/prod_protocol_rtc.h
+++ b/libtransport/src/protocols/prod_protocol_rtc.h
@@ -60,8 +60,9 @@ class RTCProductionProtocol : public ProductionProtocol {
// packet handlers
void onInterest(Interest &interest) override;
void onError(std::error_code ec) override;
+ void processInterest(uint32_t interest_seg, uint32_t lifetime);
void produceInternal(std::shared_ptr<ContentObject> &&content_object,
- const Name &content_name);
+ const Name &content_name, bool fec = false);
void sendNack(uint32_t sequence);
// stats
@@ -75,20 +76,27 @@ class RTCProductionProtocol : public ProductionProtocol {
void scheduleQueueTimer(uint64_t wait);
void interestQueueTimer();
+ // FEC functions
+ void onFecPackets(std::vector<std::pair<uint32_t, fec::buffer>> &packets);
+ fec::buffer getBuffer(std::size_t size);
+
core::Name flow_name_;
- uint32_t current_seg_; // seq id of the next packet produced
- uint32_t prod_label_; // path lable of the producer
- uint16_t header_size_; // hicn header size
+ uint32_t current_seg_; // seq id of the next packet produced
+ uint32_t prod_label_; // path lable of the producer
+ uint32_t cache_label_; // path lable for content from the producer cache
+ uint16_t data_header_size_; // hicn data header size
- uint32_t produced_bytes_; // bytes produced in the last round
- uint32_t produced_packets_; // packet produed in the last round
+ uint32_t produced_bytes_; // bytes produced in the last round
+ uint32_t produced_packets_; // packet produed in the last round
+ uint32_t produced_fec_packets_; // fec packets produced last round
uint32_t max_packet_production_; // never exceed this number of packets
// without update stats
- uint32_t bytes_production_rate_; // bytes per sec
- uint32_t packets_production_rate_; // pps
+ uint32_t bytes_production_rate_; // bytes per sec
+ uint32_t packets_production_rate_; // pps
+ uint32_t fec_packets_production_rate_; // pps
std::unique_ptr<asio::steady_timer> round_timer_;
uint64_t last_round_;
@@ -120,6 +128,9 @@ class RTCProductionProtocol : public ProductionProtocol {
// impossible to know the state of the consumers so it should not be used.
bool consumer_in_sync_;
interface::ProducerInterestCallback on_consumer_in_sync_;
+
+ // Save FEC packets here before sending them
+ std::queue<ContentObject::Ptr> pending_fec_packets_;
};
} // namespace protocol
diff --git a/libtransport/src/protocols/production_protocol.cc b/libtransport/src/protocols/production_protocol.cc
index 8addf52d1..6b317d47d 100644
--- a/libtransport/src/protocols/production_protocol.cc
+++ b/libtransport/src/protocols/production_protocol.cc
@@ -26,6 +26,7 @@ ProductionProtocol::ProductionProtocol(
implementation::ProducerSocket *icn_socket)
: socket_(icn_socket),
is_running_(false),
+ fec_encoder_(nullptr),
on_interest_input_(VOID_HANDLER),
on_interest_dropped_input_buffer_(VOID_HANDLER),
on_interest_inserted_input_buffer_(VOID_HANDLER),
@@ -36,7 +37,8 @@ ProductionProtocol::ProductionProtocol(
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) {
+ on_content_produced_(VOID_HANDLER),
+ fec_type_(fec::FECType::UNKNOWN) {
socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
// TODO add statistics for producer
// socket_->getSocketOption(OtherOptions::STATISTICS, &stats_);
@@ -75,6 +77,9 @@ int ProductionProtocol::start() {
&on_content_produced_);
socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
+ socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_);
+ socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
+ making_manifest_);
bool first = true;
diff --git a/libtransport/src/protocols/production_protocol.h b/libtransport/src/protocols/production_protocol.h
index 780972321..7366311eb 100644
--- a/libtransport/src/protocols/production_protocol.h
+++ b/libtransport/src/protocols/production_protocol.h
@@ -20,6 +20,8 @@
#include <hicn/transport/interfaces/statistics.h>
#include <hicn/transport/utils/object_pool.h>
#include <implementation/socket.h>
+#include <protocols/fec_base.h>
+#include <protocols/fec_utils.h>
#include <utils/content_store.h>
#include <atomic>
@@ -67,6 +69,27 @@ class ProductionProtocol : public Portal::ProducerCallback {
virtual void onInterest(core::Interest &i) override = 0;
virtual void onError(std::error_code ec) override{};
+ template <typename FECHandler, typename AllocatorHandler>
+ void enableFEC(FECHandler &&fec_handler,
+ AllocatorHandler &&allocator_handler) {
+ if (!fec_encoder_) {
+ // Try to get FEC from environment
+ if (const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE")) {
+ LOG(INFO) << "Using FEC " << fec_str;
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str);
+ }
+
+ if (fec_type_ == fec::FECType::UNKNOWN) {
+ return;
+ }
+
+ fec_encoder_ = fec::FECUtils::getEncoder(fec_type_, 1);
+ fec_encoder_->setFECCallback(std::forward<FECHandler>(fec_handler));
+ fec_encoder_->setBufferCallback(
+ std::forward<AllocatorHandler>(allocator_handler));
+ }
+ }
+
protected:
implementation::ProducerSocket *socket_;
@@ -78,6 +101,7 @@ class ProductionProtocol : public Portal::ProducerCallback {
std::shared_ptr<Portal> portal_;
std::atomic<bool> is_running_;
interface::ProductionStatistics *stats_;
+ std::unique_ptr<fec::ProducerFEC> fec_encoder_;
// Callbacks
interface::ProducerInterestCallback *on_interest_input_;
@@ -101,7 +125,12 @@ class ProductionProtocol : public Portal::ProducerCallback {
// List ot routes served by current producer protocol
std::list<Prefix> served_namespaces_;
+ // Signature and manifest
+ std::shared_ptr<auth::Signer> signer_;
+ bool making_manifest_;
+
bool is_async_;
+ fec::FECType fec_type_;
};
} // end namespace protocol
diff --git a/libtransport/src/protocols/protocol.cc b/libtransport/src/protocols/protocol.cc
deleted file mode 100644
index 451fef80d..000000000
--- a/libtransport/src/protocols/protocol.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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 <implementation/socket_consumer.h>
-#include <protocols/protocol.h>
-
-namespace transport {
-
-namespace protocol {
-
-using namespace interface;
-
-TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket,
- Reassembly *reassembly_protocol)
- : socket_(icn_socket),
- reassembly_protocol_(reassembly_protocol),
- index_manager_(
- std::make_unique<IndexManager>(socket_, this, reassembly_protocol)),
- is_running_(false),
- is_first_(false),
- on_interest_retransmission_(VOID_HANDLER),
- 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),
- stats_summary_(VOID_HANDLER),
- verification_failed_callback_(VOID_HANDLER),
- on_payload_(VOID_HANDLER) {
- socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
- socket_->getSocketOption(OtherOptions::STATISTICS, &stats_);
-}
-
-int TransportProtocol::start() {
- // If the protocol is already running, return otherwise set as running
- if (is_running_) return -1;
-
- // Get all callbacks references before starting
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION,
- &on_interest_retransmission_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
- &on_interest_output_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED,
- &on_interest_timeout_);
- socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED,
- &on_interest_satisfied_);
- socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
- &on_content_object_input_);
- socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
- &on_content_object_verification_);
- socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
- &stats_summary_);
- socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED,
- &verification_failed_callback_);
- socket_->getSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
- &on_payload_);
- socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
-
- // Set it is the first time we schedule an interest
- is_first_ = true;
-
- // Reset the protocol state machine
- reset();
- // Schedule next interests
- scheduleNextInterests();
-
- is_first_ = false;
-
- // Set the protocol as running
- is_running_ = true;
-
- if (!is_async_) {
- // Start Event loop
- portal_->runEventsLoop();
-
- // Not running anymore
- is_running_ = false;
- }
-
- return 0;
-}
-
-void TransportProtocol::stop() {
- is_running_ = false;
-
- if (!is_async_) {
- portal_->stopEventsLoop();
- } else {
- portal_->clear();
- }
-}
-
-void TransportProtocol::resume() {
- if (is_running_) return;
-
- is_running_ = true;
-
- scheduleNextInterests();
-
- portal_->runEventsLoop();
-
- is_running_ = false;
-}
-
-void TransportProtocol::onContentReassembled(std::error_code ec) {
- stop();
-
- if (!on_payload_) {
- throw errors::RuntimeException(
- "The read callback must be installed in the transport before "
- "starting "
- "the content retrieval.");
- }
-
- if (!ec) {
- on_payload_->readSuccess(stats_->getBytesRecv());
- } else {
- on_payload_->readError(ec);
- }
-}
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/protocol.h b/libtransport/src/protocols/protocol.h
deleted file mode 100644
index 73a0a2c64..000000000
--- a/libtransport/src/protocols/protocol.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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/callbacks.h>
-#include <hicn/transport/interfaces/socket_consumer.h>
-#include <hicn/transport/interfaces/statistics.h>
-#include <hicn/transport/utils/object_pool.h>
-#include <implementation/socket.h>
-#include <protocols/data_processing_events.h>
-#include <protocols/indexer.h>
-#include <protocols/packet_manager.h>
-#include <protocols/reassembly.h>
-
-#include <atomic>
-
-namespace transport {
-
-namespace protocol {
-
-using namespace core;
-
-class IndexVerificationManager;
-
-using ReadCallback = interface::ConsumerSocket::ReadCallback;
-
-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 implementation::BasePortal::ConsumerCallback,
- public PacketManager<Interest>,
- public ContentObjectProcessingEventCallback {
- static constexpr std::size_t interest_pool_size = 4096;
-
- friend class ManifestIndexManager;
-
- public:
- TransportProtocol(implementation::ConsumerSocket *icn_socket,
- Reassembly *reassembly_protocol);
-
- virtual ~TransportProtocol() = default;
-
- TRANSPORT_ALWAYS_INLINE bool isRunning() { return is_running_; }
-
- virtual int start();
-
- virtual void stop();
-
- virtual void resume();
-
- virtual bool verifyKeyPackets() = 0;
-
- virtual void scheduleNextInterests() = 0;
-
- // Events generated by the indexing
- virtual void onContentReassembled(std::error_code ec);
- virtual void onPacketDropped(
- Interest::Ptr &&interest,
- ContentObject::Ptr &&content_object) override = 0;
- virtual void onReassemblyFailed(std::uint32_t missing_segment) override = 0;
-
- protected:
- // Consumer Callback
- virtual void reset() = 0;
- virtual void onContentObject(Interest::Ptr &&i,
- ContentObject::Ptr &&c) override = 0;
- virtual void onTimeout(Interest::Ptr &&i) override = 0;
- virtual void onError(std::error_code ec) override {}
-
- protected:
- implementation::ConsumerSocket *socket_;
- std::unique_ptr<Reassembly> reassembly_protocol_;
- std::unique_ptr<IndexManager> index_manager_;
- std::shared_ptr<implementation::BasePortal> portal_;
- std::atomic<bool> is_running_;
- // True if it si the first time we schedule an interest
- std::atomic<bool> is_first_;
- interface::TransportStatistics *stats_;
-
- // Callbacks
- interface::ConsumerInterestCallback *on_interest_retransmission_;
- interface::ConsumerInterestCallback *on_interest_output_;
- interface::ConsumerInterestCallback *on_interest_timeout_;
- interface::ConsumerInterestCallback *on_interest_satisfied_;
- interface::ConsumerContentObjectCallback *on_content_object_input_;
- interface::ConsumerContentObjectVerificationCallback
- *on_content_object_verification_;
- interface::ConsumerContentObjectCallback *on_content_object_;
- interface::ConsumerTimerCallback *stats_summary_;
- interface::ConsumerContentObjectVerificationFailedCallback
- *verification_failed_callback_;
- ReadCallback *on_payload_;
-
- bool is_async_;
-};
-
-} // end namespace protocol
-} // end namespace transport
diff --git a/libtransport/src/protocols/raaqm.cc b/libtransport/src/protocols/raaqm.cc
index bc8500227..1247af400 100644
--- a/libtransport/src/protocols/raaqm.cc
+++ b/libtransport/src/protocols/raaqm.cc
@@ -17,7 +17,7 @@
#include <hicn/transport/interfaces/socket_consumer.h>
#include <implementation/socket_consumer.h>
#include <protocols/errors.h>
-#include <protocols/indexer.h>
+#include <protocols/index_manager_bytestream.h>
#include <protocols/raaqm.h>
#include <cstdlib>
@@ -31,7 +31,8 @@ using namespace interface;
RaaqmTransportProtocol::RaaqmTransportProtocol(
implementation::ConsumerSocket *icn_socket)
- : TransportProtocol(icn_socket, new ByteStreamReassembly(icn_socket, this)),
+ : TransportProtocol(icn_socket, new IndexManager(icn_socket, this),
+ new ByteStreamReassembly(icn_socket, this)),
current_window_size_(1),
interests_in_flight_(0),
cur_path_(nullptr),
@@ -47,11 +48,34 @@ RaaqmTransportProtocol::~RaaqmTransportProtocol() {
}
}
-int RaaqmTransportProtocol::start() {
+void RaaqmTransportProtocol::reset() {
+ // Set first segment to retrieve
+ TransportProtocol::reset();
+ core::Name *name;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
+ indexer_verifier_->setFirstSuffix(name->getSuffix());
+ std::queue<uint32_t> empty;
+ std::swap(interest_to_retransmit_, empty);
+ stats_->reset();
+
+ // Reset protocol variables
+ interests_in_flight_ = 0;
+ t0_ = utils::SteadyClock::now();
+
+ // Optionally reset congestion window
+ bool reset_window;
+ socket_->getSocketOption(RaaqmTransportOptions::PER_SESSION_CWINDOW_RESET,
+ reset_window);
+ if (reset_window) {
+ current_window_size_ = 1;
+ }
+
+ // Reset rate estimator
if (rate_estimator_) {
rate_estimator_->onStart();
}
+ // If not cur_path exists, create one
if (!cur_path_) {
// RAAQM
double drop_factor;
@@ -94,37 +118,6 @@ int RaaqmTransportProtocol::start() {
cur_path_ = cur_path.get();
path_table_[default_values::path_id] = std::move(cur_path);
}
-
- portal_->setConsumerCallback(this);
- return TransportProtocol::start();
-}
-
-void RaaqmTransportProtocol::resume() { return TransportProtocol::resume(); }
-
-void RaaqmTransportProtocol::reset() {
- // Set first segment to retrieve
- core::Name *name;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
- index_manager_->reset();
- index_manager_->setFirstSuffix(name->getSuffix());
- std::queue<Interest::Ptr> empty;
- std::swap(interest_to_retransmit_, empty);
- stats_->reset();
-
- // Reset reassembly component
- reassembly_protocol_->reInitialize();
-
- // Reset protocol variables
- interests_in_flight_ = 0;
- t0_ = utils::SteadyClock::now();
-
- // Optionally reset congestion window
- bool reset_window;
- socket_->getSocketOption(RaaqmTransportOptions::PER_SESSION_CWINDOW_RESET,
- reset_window);
- if (reset_window) {
- current_window_size_ = 1;
- }
}
void RaaqmTransportProtocol::increaseWindow() {
@@ -194,9 +187,8 @@ void RaaqmTransportProtocol::init() {
lte_delay_ = 15000;
if (!is) {
- TRANSPORT_LOGW(
- "WARNING: RAAQM parameters not found at %s, set default values",
- RAAQM_CONFIG_PATH);
+ LOG(WARNING) << "RAAQM parameters not found at " << RAAQM_CONFIG_PATH
+ << ", set default values";
return;
}
@@ -322,12 +314,9 @@ void RaaqmTransportProtocol::init() {
is.close();
}
-void RaaqmTransportProtocol::onContentObject(Interest &interest,
- ContentObject &content_object) {
- // Check whether makes sense to continue
- if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
- return;
- }
+void RaaqmTransportProtocol::onContentObjectReceived(
+ Interest &interest, ContentObject &content_object, std::error_code &ec) {
+ uint32_t incremental_suffix = content_object.getName().getSuffix();
// Call application-defined callbacks
if (*on_content_object_input_) {
@@ -338,18 +327,12 @@ void RaaqmTransportProtocol::onContentObject(Interest &interest,
(*on_interest_satisfied_)(*socket_->getInterface(), interest);
}
+ ec = make_error_code(protocol_error::success);
+
if (content_object.getPayloadType() == PayloadType::DATA) {
stats_->updateBytesRecv(content_object.payloadSize());
}
- onContentSegment(interest, content_object);
- scheduleNextInterests();
-}
-
-void RaaqmTransportProtocol::onContentSegment(Interest &interest,
- ContentObject &content_object) {
- uint32_t incremental_suffix = content_object.getName().getSuffix();
-
// Decrease in-flight interests
interests_in_flight_--;
@@ -358,11 +341,13 @@ void RaaqmTransportProtocol::onContentSegment(Interest &interest,
afterContentReception(interest, content_object);
}
- index_manager_->onContentObject(interest, content_object);
+ // Schedule next interests
+ scheduleNextInterests();
}
void RaaqmTransportProtocol::onPacketDropped(Interest &interest,
- ContentObject &content_object) {
+ ContentObject &content_object,
+ const std::error_code &reason) {
uint32_t max_rtx = 0;
socket_->getSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, max_rtx);
@@ -380,16 +365,15 @@ void RaaqmTransportProtocol::onPacketDropped(Interest &interest,
(*on_interest_output_)(*socket_->getInterface(), interest);
}
- if (!is_running_) {
+ if (!isRunning()) {
return;
}
interest_retransmissions_[segment & mask]++;
- interest_to_retransmit_.push(interest.shared_from_this());
+ interest_to_retransmit_.push(segment);
} else {
- TRANSPORT_LOGE(
- "Stop: received not trusted packet %llu times",
- (unsigned long long)interest_retransmissions_[segment & mask]);
+ LOG(ERROR) << "Stop: received not trusted packet "
+ << interest_retransmissions_[segment & mask] << " times";
onContentReassembled(
make_error_code(protocol_error::max_retransmissions_error));
}
@@ -399,23 +383,25 @@ void RaaqmTransportProtocol::onReassemblyFailed(std::uint32_t missing_segment) {
}
-void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
- checkForStalePaths();
-
- const Name &n = interest->getName();
-
- TRANSPORT_LOGW("Timeout on content %s", n.toString().c_str());
+void RaaqmTransportProtocol::sendInterest(
+ const Name &interest_name,
+ std::array<uint32_t, MAX_AGGREGATED_INTEREST> *additional_suffixes,
+ uint32_t len) {
+ interests_in_flight_++;
+ interest_retransmissions_[interest_name.getSuffix() & mask]++;
+ TransportProtocol::sendInterest(interest_name, additional_suffixes, len);
+}
- if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
- return;
- }
+void RaaqmTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
+ const Name &n) {
+ checkForStalePaths();
interests_in_flight_--;
uint64_t segment = n.getSuffix();
// Do not retransmit interests asking contents that do not exist.
- if (segment > index_manager_->getFinalSuffix()) {
+ if (segment > indexer_verifier_->getFinalSuffix()) {
return;
}
@@ -436,32 +422,34 @@ void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
(*on_interest_retransmission_)(*socket_->getInterface(), *interest);
}
- if (!is_running_) {
+ if (!isRunning()) {
return;
}
- interest_retransmissions_[segment & mask]++;
- interest_to_retransmit_.push(std::move(interest));
-
+ interest_to_retransmit_.push(segment);
scheduleNextInterests();
} else {
- TRANSPORT_LOGE("Stop: reached max retx limit.");
+ LOG(ERROR) << "Stop: reached max retx limit.";
onContentReassembled(std::make_error_code(std::errc(std::errc::io_error)));
}
}
void RaaqmTransportProtocol::scheduleNextInterests() {
- bool cancel = (!is_running_ && !is_first_) || !schedule_interests_;
+ bool cancel = (!isRunning() && !is_first_) || !schedule_interests_;
if (TRANSPORT_EXPECT_FALSE(cancel)) {
schedule_interests_ = true;
return;
}
+ core::Name *name;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
+
if (TRANSPORT_EXPECT_FALSE(interests_in_flight_ >= current_window_size_ &&
interest_to_retransmit_.size() > 0)) {
// send at least one interest if there are retransmissions to perform and
// there is no space left in the window
- sendInterest(std::move(interest_to_retransmit_.front()));
+ auto suffix = interest_to_retransmit_.front();
+ sendInterest(name->setSuffix(suffix));
interest_to_retransmit_.pop();
}
@@ -470,55 +458,25 @@ void RaaqmTransportProtocol::scheduleNextInterests() {
// Send the interest needed for filling the window
while (interests_in_flight_ < current_window_size_) {
if (interest_to_retransmit_.size() > 0) {
- sendInterest(std::move(interest_to_retransmit_.front()));
+ auto suffix = interest_to_retransmit_.front();
+ sendInterest(name->setSuffix(suffix));
interest_to_retransmit_.pop();
} else {
- if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
- TRANSPORT_LOGI("Adios");
+ if (TRANSPORT_EXPECT_FALSE(!isRunning() && !is_first_)) {
break;
}
- index = index_manager_->getNextSuffix();
+ index = indexer_verifier_->getNextSuffix();
if (index == IndexManager::invalid_index) {
break;
}
- sendInterest(index);
+ interest_retransmissions_[index & mask] = ~0;
+ sendInterest(name->setSuffix(index));
}
}
}
-void RaaqmTransportProtocol::sendInterest(std::uint64_t next_suffix) {
- auto interest = core::PacketManager<>::getInstance().getPacket<Interest>();
- core::Name *name;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
- name->setSuffix((uint32_t)next_suffix);
- interest->setName(*name);
-
- uint32_t interest_lifetime;
- socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
- interest_lifetime);
- interest->setLifetime(interest_lifetime);
-
- if (*on_interest_output_) {
- on_interest_output_->operator()(*socket_->getInterface(), *interest);
- }
- // This is set to ~0 so that the next interest_retransmissions_ + 1,
- // performed by sendInterest, will result in 0
- interest_retransmissions_[next_suffix & mask] = ~0;
- interest_timepoints_[next_suffix & mask] = utils::SteadyClock::now();
-
- sendInterest(std::move(interest));
-}
-
-void RaaqmTransportProtocol::sendInterest(Interest::Ptr &&interest) {
- interests_in_flight_++;
- interest_retransmissions_[interest->getName().getSuffix() & mask]++;
-
- TRANSPORT_LOGD("Send interest %s", interest->getName().toString().c_str());
- portal_->sendInterest(std::move(interest));
-}
-
void RaaqmTransportProtocol::onContentReassembled(std::error_code ec) {
rate_estimator_->onDownloadFinished();
TransportProtocol::onContentReassembled(ec);
diff --git a/libtransport/src/protocols/raaqm.h b/libtransport/src/protocols/raaqm.h
index be477d39f..ffbb30d3a 100644
--- a/libtransport/src/protocols/raaqm.h
+++ b/libtransport/src/protocols/raaqm.h
@@ -32,13 +32,12 @@ namespace protocol {
class RaaqmTransportProtocol : public TransportProtocol,
public CWindowProtocol {
public:
- RaaqmTransportProtocol(implementation::ConsumerSocket *icnet_socket);
+ RaaqmTransportProtocol(implementation::ConsumerSocket *icn_socket);
~RaaqmTransportProtocol();
- int start() override;
-
- void resume() override;
+ using TransportProtocol::start;
+ using TransportProtocol::stop;
void reset() override;
@@ -62,35 +61,24 @@ class RaaqmTransportProtocol : public TransportProtocol,
private:
void init();
- void onContentObject(Interest &i, ContentObject &c) override;
-
- void onContentSegment(Interest &interest, ContentObject &content_object);
-
- void onPacketDropped(Interest &interest,
- ContentObject &content_object) override;
-
+ void onContentObjectReceived(Interest &i, ContentObject &c,
+ std::error_code &ec) override;
+ void onPacketDropped(Interest &interest, ContentObject &content_object,
+ const std::error_code &reason) override;
void onReassemblyFailed(std::uint32_t missing_segment) override;
-
- void onTimeout(Interest::Ptr &&i) override;
-
+ void onInterestTimeout(Interest::Ptr &i, const Name &n) override;
virtual void scheduleNextInterests() override;
-
- void sendInterest(std::uint64_t next_suffix);
-
- void sendInterest(Interest::Ptr &&interest);
+ void sendInterest(const Name &interest_name,
+ std::array<uint32_t, MAX_AGGREGATED_INTEREST>
+ *additional_suffixes = nullptr,
+ uint32_t len = 0) override;
void onContentReassembled(std::error_code ec) override;
-
void updateRtt(uint64_t segment);
-
void RAAQM();
-
void updatePathTable(const ContentObject &content_object);
-
void checkDropProbability();
-
void checkForStalePaths();
-
void printRtt();
protected:
@@ -100,7 +88,7 @@ class RaaqmTransportProtocol : public TransportProtocol,
uint64_t interests_in_flight_;
std::array<std::uint32_t, buffer_size> interest_retransmissions_;
std::array<utils::TimePoint, buffer_size> interest_timepoints_;
- std::queue<Interest::Ptr> interest_to_retransmit_;
+ std::queue<uint32_t> interest_to_retransmit_;
private:
/**
diff --git a/libtransport/src/protocols/rate_estimation.cc b/libtransport/src/protocols/rate_estimation.cc
index 5ca925760..2337e18be 100644
--- a/libtransport/src/protocols/rate_estimation.cc
+++ b/libtransport/src/protocols/rate_estimation.cc
@@ -13,8 +13,8 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/interfaces/socket_options_default_values.h>
-#include <hicn/transport/utils/log.h>
#include <protocols/rate_estimation.h>
#include <thread>
@@ -115,12 +115,12 @@ void InterRttEstimator::onRttUpdate(double rtt) {
if (!thread_is_running_) {
my_th_ = (pthread_t *)malloc(sizeof(pthread_t));
if (!my_th_) {
- TRANSPORT_LOGE("Error allocating thread.");
+ LOG(ERROR) << "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");
+ LOG(ERROR) << "Error creating the thread";
my_th_ = NULL;
}
thread_is_running_ = true;
diff --git a/libtransport/src/protocols/reassembly.cc b/libtransport/src/protocols/reassembly.cc
index 0e59832dc..ce24fce1b 100644
--- a/libtransport/src/protocols/reassembly.cc
+++ b/libtransport/src/protocols/reassembly.cc
@@ -31,7 +31,7 @@ void Reassembly::notifyApplication() {
interface::ConsumerCallbacksOptions::READ_CALLBACK, &read_callback);
if (TRANSPORT_EXPECT_FALSE(!read_callback)) {
- TRANSPORT_LOGE("Read callback not installed!");
+ LOG(ERROR) << "Read callback not installed!";
return;
}
diff --git a/libtransport/src/protocols/reassembly.h b/libtransport/src/protocols/reassembly.h
index 385122c53..e072ad123 100644
--- a/libtransport/src/protocols/reassembly.h
+++ b/libtransport/src/protocols/reassembly.h
@@ -46,19 +46,48 @@ class Reassembly {
virtual ~Reassembly() = default;
+ /**
+ * Hanle reassembly of content object.
+ */
virtual void reassemble(core::ContentObject &content_object) = 0;
+
+ /**
+ * Hanle reassembly of content object.
+ */
+ virtual void reassemble(utils::MemBuf &buffer, uint32_t suffix) = 0;
+
+ /**
+ * Handle reassembly of manifest
+ */
virtual void reassemble(
std::unique_ptr<core::ContentObjectManifest> &&manifest) = 0;
+
+ /**
+ * Reset reassembler for new round
+ */
virtual void reInitialize() = 0;
- virtual void setIndexer(Indexer *indexer) { index_manager_ = indexer; }
+
+ /**
+ * Use indexer to get next segments to reassembly
+ */
+ virtual void setIndexer(Indexer *indexer) { indexer_verifier_ = indexer; }
+
+ /**
+ * Decide if it is required to pass to application buffers whose verification
+ * has been delayed (e.g. because the manifest is missing). False by default.
+ */
+ virtual bool reassembleUnverified() { return false; }
protected:
+ /**
+ * Notify application there is data to read.
+ */
virtual void notifyApplication();
protected:
implementation::ConsumerSocket *reassembly_consumer_socket_;
TransportProtocol *transport_protocol_;
- Indexer *index_manager_;
+ Indexer *indexer_verifier_;
std::unique_ptr<utils::MemBuf> read_buffer_;
};
diff --git a/libtransport/src/protocols/rtc.cc b/libtransport/src/protocols/rtc.cc
deleted file mode 100644
index a01b8daa5..000000000
--- a/libtransport/src/protocols/rtc.cc
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * 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 <implementation/socket_consumer.h>
-#include <math.h>
-#include <protocols/rtc.h>
-
-#include <random>
-
-namespace transport {
-
-namespace protocol {
-
-using namespace interface;
-
-RTCTransportProtocol::RTCTransportProtocol(
- implementation::ConsumerSocket *icn_socket)
- : TransportProtocol(icn_socket, nullptr),
- DatagramReassembly(icn_socket, this),
- inflightInterests_(1 << default_values::log_2_default_buffer_size),
- modMask_((1 << default_values::log_2_default_buffer_size) - 1) {
- icn_socket->getSocketOption(PORTAL, portal_);
- rtx_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
- probe_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
- sentinel_timer_ =
- std::make_unique<asio::steady_timer>(portal_->getIoService());
- round_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
- initParams();
-}
-
-RTCTransportProtocol::~RTCTransportProtocol() {}
-
-void RTCTransportProtocol::resume() {
- if (is_running_) return;
-
- is_running_ = true;
- inflightInterestsCount_ = 0;
-
- probeRtt();
- sentinelTimer();
- newRound();
- scheduleNextInterests();
-
- portal_->runEventsLoop();
- is_running_ = false;
-}
-
-// private
-void RTCTransportProtocol::initParams() {
- portal_->setConsumerCallback(this);
- // controller var
- currentState_ = HICN_RTC_SYNC_STATE;
-
- // cwin var
- currentCWin_ = HICN_INITIAL_CWIN;
- maxCWin_ = HICN_INITIAL_CWIN_MAX;
-
- // names/packets var
- actualSegment_ = 0;
- inflightInterestsCount_ = 0;
- interestRetransmissions_.clear();
- lastSegNacked_ = 0;
- lastReceived_ = 0;
- lastReceivedTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- lastEvent_ = lastReceivedTime_;
- highestReceived_ = 0;
- firstSequenceInRound_ = 0;
-
- rtx_timer_used_ = false;
- for (int i = 0; i < (1 << default_values::log_2_default_buffer_size); i++) {
- inflightInterests_[i] = {0};
- }
-
- // stats
- firstPckReceived_ = false;
- receivedBytes_ = 0;
- sentInterest_ = 0;
- receivedData_ = 0;
- packetLost_ = 0;
- lossRecovered_ = 0;
- avgPacketSize_ = HICN_INIT_PACKET_SIZE;
- gotNack_ = false;
- gotFutureNack_ = 0;
- rounds_ = 0;
- roundsWithoutNacks_ = 0;
- pathTable_.clear();
-
- // CC var
- estimatedBw_ = 0.0;
- lossRate_ = 0.0;
- queuingDelay_ = 0.0;
- protocolState_ = HICN_RTC_NORMAL_STATE;
-
- producerPathLabels_[0] = 0;
- producerPathLabels_[1] = 0;
- initied = false;
-
- socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
- (uint32_t)HICN_RTC_INTEREST_LIFETIME);
-}
-
-// private
-void RTCTransportProtocol::reset() {
- initParams();
- probeRtt();
- sentinelTimer();
- newRound();
-}
-
-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::newRound() {
- round_timer_->expires_from_now(std::chrono::milliseconds(HICN_ROUND_LEN));
- round_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- updateStats(HICN_ROUND_LEN);
- newRound();
- });
-}
-
-void RTCTransportProtocol::updateDelayStats(
- const ContentObject &content_object) {
- uint32_t segmentNumber = content_object.getName().getSuffix();
- uint32_t pkt = segmentNumber & modMask_;
-
- if (inflightInterests_[pkt].state != sent_) return;
-
- if (interestRetransmissions_.find(segmentNumber) !=
- interestRetransmissions_.end())
- // this packet was rtx at least once
- 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);
- auto payload = content_object.getPayload();
-
- // we collect OWD only for datapackets
- if (payload->length() != HICN_NACK_HEADER_SIZE) {
- uint64_t *senderTimeStamp = (uint64_t *)payload->data();
- int64_t OWD = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count() -
- *senderTimeStamp;
-
- pathTable_[pathLabel]->insertOwdSample(OWD);
- pathTable_[pathLabel]->computeInterArrivalGap(segmentNumber);
- } else {
- pathTable_[pathLabel]->receivedNack();
- }
-}
-
-void RTCTransportProtocol::updateStats(uint32_t round_duration) {
- if (pathTable_.empty()) return;
-
- if (receivedBytes_ != 0) {
- double bytesPerSec =
- (double)(receivedBytes_ *
- ((double)HICN_MILLI_IN_A_SEC / (double)round_duration));
- estimatedBw_ = (estimatedBw_ * HICN_ESTIMATED_BW_ALPHA) +
- ((1 - HICN_ESTIMATED_BW_ALPHA) * bytesPerSec);
- }
-
- uint64_t minRtt = UINT_MAX;
- uint64_t maxRtt = 0;
-
- for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) {
- it->second->roundEnd();
- if (it->second->isActive()) {
- if (it->second->getMinRtt() < minRtt) {
- minRtt = it->second->getMinRtt();
- producerPathLabels_[0] = it->first;
- }
- if (it->second->getMinRtt() > maxRtt) {
- maxRtt = it->second->getMinRtt();
- producerPathLabels_[1] = it->first;
- }
- }
- }
-
- if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() ||
- pathTable_.find(producerPathLabels_[1]) == pathTable_.end())
- return; // this should not happen
-
- // as a queuing delay we keep the lowest one among the two paths
- // if one path is congested the forwarder should decide to do not
- // use it so it does not make sense to inform the application
- // that maybe we have a problem
- if (pathTable_[producerPathLabels_[0]]->getQueuingDealy() <
- pathTable_[producerPathLabels_[1]]->getQueuingDealy())
- queuingDelay_ = pathTable_[producerPathLabels_[0]]->getQueuingDealy();
- else
- queuingDelay_ = pathTable_[producerPathLabels_[1]]->getQueuingDealy();
-
- if (sentInterest_ != 0 && currentState_ == HICN_RTC_NORMAL_STATE) {
- uint32_t numberTheoricallyReceivedPackets_ =
- highestReceived_ - firstSequenceInRound_;
- double lossRate = 0;
- if (numberTheoricallyReceivedPackets_ != 0)
- lossRate = (double)((double)(packetLost_ - lossRecovered_) /
- (double)numberTheoricallyReceivedPackets_);
-
- if (lossRate < 0) lossRate = 0;
-
- if (initied) {
- lossRate_ = lossRate_ * HICN_ESTIMATED_LOSSES_ALPHA +
- (lossRate * (1 - HICN_ESTIMATED_LOSSES_ALPHA));
- } else {
- lossRate_ = lossRate;
- initied = true;
- }
- }
-
- if (avgPacketSize_ == 0) avgPacketSize_ = HICN_INIT_PACKET_SIZE;
-
- // for the BDP we use the max rtt, so that we calibrate the window on the
- // RTT of the slowest path. In this way we are sure that the window will
- // never be too small
- uint32_t BDP = (uint32_t)ceil(
- (estimatedBw_ *
- (double)((double)pathTable_[producerPathLabels_[1]]->getMinRtt() /
- (double)HICN_MILLI_IN_A_SEC) *
- HICN_BANDWIDTH_SLACK_FACTOR) /
- avgPacketSize_);
- uint32_t BW = (uint32_t)ceil(estimatedBw_);
- computeMaxWindow(BW, BDP);
-
- if (*stats_summary_) {
- // Send the stats to the app
- stats_->updateQueuingDelay(queuingDelay_);
- stats_->updateLossRatio(lossRate_);
- stats_->updateAverageRtt(pathTable_[producerPathLabels_[1]]->getMinRtt());
- (*stats_summary_)(*socket_->getInterface(), *stats_);
- }
- // bound also by interest lifitime* production rate
- if (!gotNack_) {
- roundsWithoutNacks_++;
- if (currentState_ == HICN_RTC_SYNC_STATE &&
- roundsWithoutNacks_ >= HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH) {
- currentState_ = HICN_RTC_NORMAL_STATE;
- }
- } else {
- roundsWithoutNacks_ = 0;
- }
-
- updateCCState();
- updateWindow();
-
- if (queuingDelay_ > 25.0) {
- // this indicates that the client will go soon out of synch,
- // switch to synch mode
- if (currentState_ == HICN_RTC_NORMAL_STATE) {
- currentState_ = HICN_RTC_SYNC_STATE;
- }
- computeMaxWindow(BW, 0);
- increaseWindow();
- }
-
- // in any case we reset all the counters
-
- gotNack_ = false;
- gotFutureNack_ = 0;
- receivedBytes_ = 0;
- sentInterest_ = 0;
- receivedData_ = 0;
- packetLost_ = 0;
- lossRecovered_ = 0;
- rounds_++;
- firstSequenceInRound_ = highestReceived_;
-}
-
-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 = (uint32_t)ceil(
- (productionRate / avgPacketSize_) *
- (double)((double)(interestLifetime *
- HICN_INTEREST_LIFETIME_REDUCTION_FACTOR) /
- (double)HICN_MILLI_IN_A_SEC));
-
- if (currentState_ == HICN_RTC_SYNC_STATE) {
- // in this case we do not limit the window with the BDP, beacuse most
- // likely it is wrong
- maxCWin_ = maxWaintingInterest;
- return;
- }
-
- // currentState = RTC_NORMAL_STATE
- if (BDPWin != 0) {
- maxCWin_ = (uint32_t)ceil((double)BDPWin +
- (((double)BDPWin * 30.0) / 100.0)); // BDP + 30%
- } else {
- maxCWin_ = min(maxWaintingInterest, maxCWin_);
- }
-
- if (maxCWin_ < HICN_MIN_CWIN) maxCWin_ = HICN_MIN_CWIN;
-}
-
-void RTCTransportProtocol::updateWindow() {
- if (currentState_ == HICN_RTC_SYNC_STATE) return;
-
- if (estimatedBw_ == 0) return;
-
- if (currentCWin_ < maxCWin_ * 0.9) {
- currentCWin_ =
- min(maxCWin_, (uint32_t)(currentCWin_ * HICN_WIN_INCREASE_FACTOR));
- } else if (currentCWin_ > maxCWin_) {
- currentCWin_ =
- max((uint32_t)(currentCWin_ * HICN_WIN_DECREASE_FACTOR), HICN_MIN_CWIN);
- }
-}
-
-void RTCTransportProtocol::decreaseWindow() {
- // this is used only in SYNC mode
- if (currentState_ == HICN_RTC_NORMAL_STATE) return;
-
- if (gotFutureNack_ == 1)
- currentCWin_ = min((currentCWin_ - 1),
- (uint32_t)ceil((double)maxCWin_ * 0.66)); // 2/3
- else
- currentCWin_--;
-
- currentCWin_ = max(currentCWin_, HICN_MIN_CWIN);
-}
-
-void RTCTransportProtocol::increaseWindow() {
- // this is used only in SYNC mode
- if (currentState_ == HICN_RTC_NORMAL_STATE) return;
-
- // we need to be carefull to do not increase the window to much
- if (currentCWin_ < ((double)maxCWin_ * 0.7)) {
- currentCWin_ = currentCWin_ + 1; // exponential
- } else {
- currentCWin_ = min(
- maxCWin_,
- (uint32_t)ceil(currentCWin_ + (1.0 / (double)currentCWin_))); // linear
- }
-}
-
-void RTCTransportProtocol::probeRtt() {
- probe_timer_->expires_from_now(std::chrono::milliseconds(1000));
- probe_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- probeRtt();
- });
-
- // To avoid sending the first probe, because the transport is not running yet
- if (is_first_ && !is_running_) return;
-
- time_sent_probe_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
- // get a random numbe in the probe seq range
- std::default_random_engine eng((std::random_device())());
- std::uniform_int_distribution<uint32_t> idis(HICN_MIN_PROBE_SEQ,
- HICN_MAX_PROBE_SEQ);
- probe_seq_number_ = idis(eng);
- interest_name->setSuffix(probe_seq_number_);
-
- // we considere the probe as a rtx so that we do not incresea inFlightInt
- received_probe_ = false;
- TRANSPORT_LOGD("Send content interest %u (probeRtt)",
- interest_name->getSuffix());
- sendInterest(interest_name, true);
-}
-
-void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) {
- auto interest = getPacket();
- interest->setName(*interest_name);
-
- uint32_t interestLifetime = default_values::interest_lifetime;
- socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
- interestLifetime);
- interest->setLifetime(uint32_t(interestLifetime));
-
- if (*on_interest_output_) {
- (*on_interest_output_)(*socket_->getInterface(), *interest);
- }
-
- if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
- return;
- }
-
- portal_->sendInterest(std::move(interest));
-
- sentInterest_++;
-
- if (!rtx) {
- packets_in_window_[interest_name->getSuffix()] = 0;
- inflightInterestsCount_++;
- }
-}
-
-void RTCTransportProtocol::scheduleNextInterests() {
- if (!is_running_ && !is_first_) return;
-
- TRANSPORT_LOGD("----- [window %u - inflight_interests %u = %d] -----",
- currentCWin_, inflightInterestsCount_,
- currentCWin_ - inflightInterestsCount_);
-
- while (inflightInterestsCount_ < currentCWin_) {
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
-
- interest_name->setSuffix(actualSegment_);
-
- // if the producer socket is not stated (does not reply even with nacks)
- // we keep asking for something without marking anything as lost (see
- // timeout). In this way when the producer socket will start the
- // consumer socket will not miss any packet
- if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) {
- uint32_t pkt = actualSegment_ & modMask_;
- inflightInterests_[pkt].state = sent_;
- inflightInterests_[pkt].sequence = actualSegment_;
- actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
- TRANSPORT_LOGD(
- "Send content interest %u (scheduleNextInterests no replies)",
- interest_name->getSuffix());
- sendInterest(interest_name, false);
- return;
- }
-
- // we send the packet only if it is not pending yet
- // notice that this is not true for rtx packets
- if (portal_->interestIsPending(*interest_name)) {
- actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
- continue;
- }
-
- uint32_t pkt = actualSegment_ & modMask_;
- // if we already reacevied the content we don't ask it again
- if (inflightInterests_[pkt].state == received_ &&
- inflightInterests_[pkt].sequence == actualSegment_) {
- actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
- continue;
- }
-
- // same if the packet is lost
- if (inflightInterests_[pkt].state == lost_ &&
- inflightInterests_[pkt].sequence == actualSegment_) {
- actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
- continue;
- }
-
- inflightInterests_[pkt].transmissionTime =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- // here the packet can be in any state except for lost or recevied
- inflightInterests_[pkt].state = sent_;
- inflightInterests_[pkt].sequence = actualSegment_;
- actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
-
- TRANSPORT_LOGD("Send content interest %u (scheduleNextInterests)",
- interest_name->getSuffix());
- sendInterest(interest_name, false);
- }
-
- TRANSPORT_LOGD("----- end of scheduleNextInterest -----");
-}
-
-bool RTCTransportProtocol::verifyKeyPackets() {
- // Not yet implemented
- return false;
-}
-
-void RTCTransportProtocol::sentinelTimer() {
- uint32_t wait = 50;
-
- if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
- pathTable_.find(producerPathLabels_[1]) != pathTable_.end()) {
- // we have all the info to set the timers
- wait = round(pathTable_[producerPathLabels_[0]]->getInterArrivalGap());
- if (wait == 0) wait = 1;
- }
-
- sentinel_timer_->expires_from_now(std::chrono::milliseconds(wait));
- sentinel_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
-
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() ||
- pathTable_.find(producerPathLabels_[1]) == pathTable_.end()) {
- // we have no info, so we send again
-
- for (auto it = packets_in_window_.begin(); it != packets_in_window_.end();
- it++) {
- uint32_t pkt = it->first & modMask_;
- if (inflightInterests_[pkt].sequence == it->first) {
- inflightInterests_[pkt].transmissionTime = now;
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
- interest_name->setSuffix(it->first);
- it->second++;
- sendInterest(interest_name, true);
- }
- }
- } else {
- uint64_t max_waiting_time = // wait at least 50ms
- (pathTable_[producerPathLabels_[1]]->getMinRtt() -
- pathTable_[producerPathLabels_[0]]->getMinRtt()) +
- (ceil(pathTable_[producerPathLabels_[0]]->getInterArrivalGap()) * 50);
-
- if ((currentState_ == HICN_RTC_NORMAL_STATE) &&
- (inflightInterestsCount_ >= currentCWin_) &&
- ((now - lastEvent_) > max_waiting_time) && (lossRate_ >= 0.05)) {
- uint64_t RTT = pathTable_[producerPathLabels_[1]]->getMinRtt();
-
- for (auto it = packets_in_window_.begin();
- it != packets_in_window_.end(); it++) {
- uint32_t pkt = it->first & modMask_;
- if (inflightInterests_[pkt].sequence == it->first &&
- ((now - inflightInterests_[pkt].transmissionTime) >= RTT)) {
- inflightInterests_[pkt].transmissionTime = now;
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
- interest_name->setSuffix(it->first);
- it->second++;
- sendInterest(interest_name, true);
- }
- }
- }
- }
-
- sentinelTimer();
- });
-}
-void RTCTransportProtocol::addRetransmissions(uint32_t val) {
- // add only val in the rtx list
- addRetransmissions(val, val + 1);
-}
-
-void RTCTransportProtocol::addRetransmissions(uint32_t start, uint32_t stop) {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- bool new_rtx = false;
- for (uint32_t i = start; i < stop; i++) {
- auto it = interestRetransmissions_.find(i);
- if (it == interestRetransmissions_.end()) {
- uint32_t pkt = i & modMask_;
- if (lastSegNacked_ <= i && inflightInterests_[pkt].state != received_) {
- // it must be larger than the last past nack received
- packetLost_++;
- interestRetransmissions_[i] = 0;
- uint32_t pkt = i & modMask_;
- // we reset the transmission time setting to now, so that rtx will
- // happne in one RTT on waint one inter arrival gap
- inflightInterests_[pkt].transmissionTime = now;
- new_rtx = true;
- }
- } // if the retransmission is already there the rtx timer will
- // take care of it
- }
-
- // in case a new rtx is added to the map we need to run checkRtx()
- if (new_rtx) {
- if (rtx_timer_used_) {
- // if a timer is pending we need to delete it
- rtx_timer_->cancel();
- rtx_timer_used_ = false;
- }
- checkRtx();
- }
-}
-
-uint64_t RTCTransportProtocol::retransmit() {
- auto it = interestRetransmissions_.begin();
-
- // cut len to max HICN_MAX_RTX_SIZE
- // since we use a map, the smaller (and so the older) sequence number are at
- // the beginnin of the map
- while (interestRetransmissions_.size() > HICN_MAX_RTX_SIZE) {
- it = interestRetransmissions_.erase(it);
- }
-
- it = interestRetransmissions_.begin();
- uint64_t smallest_timeout = ULONG_MAX;
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- while (it != interestRetransmissions_.end()) {
- uint32_t pkt = it->first & modMask_;
-
- if (inflightInterests_[pkt].sequence != it->first) {
- // this packet is not anymore in the inflight buffer, erase it
- it = interestRetransmissions_.erase(it);
- continue;
- }
-
- // we retransmitted the packet too many times
- if (it->second >= HICN_MAX_RTX) {
- it = interestRetransmissions_.erase(it);
- continue;
- }
-
- // this packet is too old
- if ((lastReceived_ > it->first) &&
- (lastReceived_ - it->first) > HICN_MAX_RTX_MAX_AGE) {
- it = interestRetransmissions_.erase(it);
- continue;
- }
-
- uint64_t rtx_time = now;
-
- if (it->second == 0) {
- // first rtx
- if (producerPathLabels_[0] != producerPathLabels_[1]) {
- // multipath
- if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
- pathTable_.find(producerPathLabels_[1]) != pathTable_.end() &&
- (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() <
- HICN_MIN_INTER_ARRIVAL_GAP)) {
- rtx_time = lastReceivedTime_ +
- (pathTable_[producerPathLabels_[1]]->getMinRtt() -
- pathTable_[producerPathLabels_[0]]->getMinRtt()) +
- pathTable_[producerPathLabels_[0]]->getInterArrivalGap();
- } // else low rate producer, send it immediatly
- } else {
- // single path
- if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
- (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() <
- HICN_MIN_INTER_ARRIVAL_GAP)) {
- rtx_time = lastReceivedTime_ +
- pathTable_[producerPathLabels_[0]]->getInterArrivalGap();
- } // else low rate producer send immediatly
- }
- } else {
- // second or plus rtx, wait for the min rtt
- if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end()) {
- uint64_t sent_time = inflightInterests_[pkt].transmissionTime;
- rtx_time = sent_time + pathTable_[producerPathLabels_[0]]->getMinRtt();
- } // if we don't have info we send it immediatly
- }
-
- if (now >= rtx_time) {
- inflightInterests_[pkt].transmissionTime = now;
- it->second++;
-
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
- interest_name->setSuffix(it->first);
- TRANSPORT_LOGD("Send content interest %u (retransmit)",
- interest_name->getSuffix());
- sendInterest(interest_name, true);
- } else if (rtx_time < smallest_timeout) {
- smallest_timeout = rtx_time;
- }
-
- ++it;
- }
- return smallest_timeout;
-}
-
-void RTCTransportProtocol::checkRtx() {
- if (interestRetransmissions_.empty()) {
- rtx_timer_used_ = false;
- return;
- }
-
- uint64_t next_timeout = retransmit();
- uint64_t wait = 1;
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- if (next_timeout != ULONG_MAX && now < next_timeout) {
- wait = next_timeout - now;
- }
- rtx_timer_used_ = true;
- rtx_timer_->expires_from_now(std::chrono::milliseconds(wait));
- rtx_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- rtx_timer_used_ = false;
- checkRtx();
- });
-}
-
-void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
- uint32_t segmentNumber = interest->getName().getSuffix();
-
- if (segmentNumber >= HICN_MIN_PROBE_SEQ) {
- // this is a timeout on a probe, do nothing
- return;
- }
-
- uint32_t pkt = segmentNumber & modMask_;
-
- if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) {
- // we do nothing, and we keep asking the same stuff over
- // and over until we get at least a packet
- inflightInterestsCount_--;
- lastEvent_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- packets_in_window_.erase(segmentNumber);
- scheduleNextInterests();
- return;
- }
-
- if (inflightInterests_[pkt].state == sent_) {
- lastEvent_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- packets_in_window_.erase(segmentNumber);
- inflightInterestsCount_--;
- }
-
- // check how many times we sent this packet
- auto it = interestRetransmissions_.find(segmentNumber);
- if (it != interestRetransmissions_.end() && it->second >= HICN_MAX_RTX) {
- inflightInterests_[pkt].state = lost_;
- }
-
- if (inflightInterests_[pkt].state == sent_) {
- inflightInterests_[pkt].state = timeout1_;
- } else if (inflightInterests_[pkt].state == timeout1_) {
- inflightInterests_[pkt].state = timeout2_;
- } else if (inflightInterests_[pkt].state == timeout2_) {
- inflightInterests_[pkt].state = lost_;
- }
-
- if (inflightInterests_[pkt].state == lost_) {
- interestRetransmissions_.erase(segmentNumber);
- } else {
- addRetransmissions(segmentNumber);
- }
-
- scheduleNextInterests();
-}
-
-bool RTCTransportProtocol::onNack(const ContentObject &content_object,
- bool rtx) {
- uint32_t *payload = (uint32_t *)content_object.getPayload()->data();
- uint32_t productionSeg = *payload;
- uint32_t productionRate = *(++payload);
- uint32_t nackSegment = content_object.getName().getSuffix();
-
- bool old_nack = false;
-
- // if we did not received anything between lastReceived_ + 1 and productionSeg
- // most likelly some packets got lost
- if (lastReceived_ != 0) {
- addRetransmissions(lastReceived_ + 1, productionSeg);
- }
-
- if (!rtx) {
- gotNack_ = true;
- // we synch the estimated production rate with the actual one
- estimatedBw_ = (double)productionRate;
- }
-
- if (productionSeg > nackSegment) {
- // we are asking for stuff produced in the past
- actualSegment_ = max(productionSeg, actualSegment_) % HICN_MIN_PROBE_SEQ;
-
- if (!rtx) {
- if (currentState_ == HICN_RTC_NORMAL_STATE) {
- currentState_ = HICN_RTC_SYNC_STATE;
- }
-
- computeMaxWindow(productionRate, 0);
- increaseWindow();
- }
-
- lastSegNacked_ = productionSeg;
- old_nack = true;
-
- } else if (productionSeg < nackSegment) {
- actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ;
-
- if (!rtx) {
- // we are asking stuff in the future
- gotFutureNack_++;
- computeMaxWindow(productionRate, 0);
- decreaseWindow();
-
- if (currentState_ == HICN_RTC_SYNC_STATE) {
- currentState_ = HICN_RTC_NORMAL_STATE;
- }
- }
- } else {
- // we are asking the right thing, but the producer is slow
- // keep doing the same until the packet is produced
- actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ;
- }
-
- return old_nack;
-}
-
-void RTCTransportProtocol::onContentObject(
- Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
- // as soon as we get a packet firstPckReceived_ will never be false
- firstPckReceived_ = true;
-
- auto payload = content_object->getPayload();
- uint32_t payload_size = (uint32_t)payload->length();
- uint32_t segmentNumber = content_object->getName().getSuffix();
- uint32_t pkt = segmentNumber & modMask_;
-
- if (*on_content_object_input_) {
- (*on_content_object_input_)(*socket_->getInterface(), *content_object);
- }
-
- if (segmentNumber >= HICN_MIN_PROBE_SEQ) {
- TRANSPORT_LOGD("Received probe %u", segmentNumber);
- if (segmentNumber == probe_seq_number_ && !received_probe_) {
- received_probe_ = true;
-
- uint32_t pathLabel = content_object->getPathLabel();
- if (pathTable_.find(pathLabel) == pathTable_.end()) {
- std::shared_ptr<RTCDataPath> newPath = std::make_shared<RTCDataPath>();
- pathTable_[pathLabel] = newPath;
- }
-
- // this is the expected probe, update the RTT and drop the packet
- uint64_t RTT = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count() -
- time_sent_probe_;
-
- pathTable_[pathLabel]->insertRttSample(RTT);
- pathTable_[pathLabel]->receivedNack();
- }
- return;
- }
-
- // check if the packet is a rtx
- bool is_rtx = false;
- if (interestRetransmissions_.find(segmentNumber) !=
- interestRetransmissions_.end()) {
- is_rtx = true;
- } else {
- auto it_win = packets_in_window_.find(segmentNumber);
- if (it_win != packets_in_window_.end() && it_win->second != 0)
- is_rtx = true;
- }
-
- if (payload_size == HICN_NACK_HEADER_SIZE) {
- TRANSPORT_LOGD("Received nack %u", segmentNumber);
-
- if (inflightInterests_[pkt].state == sent_) {
- lastEvent_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- packets_in_window_.erase(segmentNumber);
- inflightInterestsCount_--;
- }
-
- bool old_nack = false;
-
- if (!is_rtx) {
- // this is not a retransmitted packet
- old_nack = onNack(*content_object, false);
- updateDelayStats(*content_object);
- } else {
- old_nack = onNack(*content_object, true);
- }
-
- // the nacked_ state is used only to avoid to decrease
- // inflightInterestsCount_ multiple times. In fact, every time that we
- // receive an event related to an interest (timeout, nacked, content) we
- // cange the state. In this way we are sure that we do not decrease twice
- // the counter
- if (old_nack) {
- inflightInterests_[pkt].state = lost_;
- interestRetransmissions_.erase(segmentNumber);
- } else {
- inflightInterests_[pkt].state = nacked_;
- }
-
- } else {
- TRANSPORT_LOGD("Received content %u", segmentNumber);
-
- avgPacketSize_ = (HICN_ESTIMATED_PACKET_SIZE * avgPacketSize_) +
- ((1 - HICN_ESTIMATED_PACKET_SIZE) * payload->length());
-
- receivedBytes_ += (uint32_t)(content_object->headerSize() +
- content_object->payloadSize());
-
- if (inflightInterests_[pkt].state == sent_) {
- lastEvent_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- packets_in_window_.erase(segmentNumber);
- inflightInterestsCount_--; // packet sent without timeouts
- }
-
- if (inflightInterests_[pkt].state == sent_ && !is_rtx) {
- // delay stats are computed only for non retransmitted data
- updateDelayStats(*content_object);
- }
-
- addRetransmissions(lastReceived_ + 1, segmentNumber);
- if (segmentNumber > highestReceived_) {
- highestReceived_ = segmentNumber;
- }
- if (segmentNumber > lastReceived_) {
- lastReceived_ = segmentNumber;
- lastReceivedTime_ =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- }
- receivedData_++;
- inflightInterests_[pkt].state = received_;
-
- auto it = interestRetransmissions_.find(segmentNumber);
- if (it != interestRetransmissions_.end()) lossRecovered_++;
-
- interestRetransmissions_.erase(segmentNumber);
-
- reassemble(std::move(content_object));
- increaseWindow();
- }
-
- scheduleNextInterests();
-}
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/rtc.h b/libtransport/src/protocols/rtc.h
deleted file mode 100644
index 9f1bcc25b..000000000
--- a/libtransport/src/protocols/rtc.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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 <protocols/datagram_reassembly.h>
-#include <protocols/protocol.h>
-#include <protocols/rtc_data_path.h>
-
-#include <map>
-#include <queue>
-#include <unordered_map>
-
-// algorithm state
-#define HICN_RTC_SYNC_STATE 0
-#define HICN_RTC_NORMAL_STATE 1
-#define HICN_ROUNDS_IN_SYNC_BEFORE_SWITCH 3
-
-// packet constants
-#define HICN_INIT_PACKET_SIZE 1300 // bytes
-#define HICN_PACKET_HEADER_SIZE 60 // bytes ipv6+tcp
-#define HICN_NACK_HEADER_SIZE 8 // bytes
-#define HICN_TIMESTAMP_SIZE 8 // bytes
-#define HICN_RTC_INTEREST_LIFETIME 1000 // ms
-
-// rtt measurement
-// normal interests for data goes from 0 to
-// HICN_MIN_PROBE_SEQ, the rest is reserverd for
-// probes
-#define HICN_MIN_PROBE_SEQ 0xefffffff
-#define HICN_MAX_PROBE_SEQ 0xffffffff
-
-// controller constant
-#define HICN_ROUND_LEN \
- 200 // ms interval of time on which
- // we take decisions / measurements
-#define HICN_MAX_RTX 10
-#define HICN_MAX_RTX_SIZE 1024
-#define HICN_MAX_RTX_MAX_AGE 10000
-#define HICN_MIN_RTT_WIN 30 // rounds
-#define HICN_MIN_INTER_ARRIVAL_GAP 100 // ms
-
-// cwin
-#define HICN_INITIAL_CWIN 1 // packets
-#define HICN_INITIAL_CWIN_MAX 100000 // packets
-#define HICN_MIN_CWIN 10 // packets
-#define HICN_WIN_INCREASE_FACTOR 1.5
-#define HICN_WIN_DECREASE_FACTOR 0.9
-
-// statistics constants
-#define HICN_BANDWIDTH_SLACK_FACTOR 1.8
-#define HICN_ESTIMATED_BW_ALPHA 0.7
-#define HICN_ESTIMATED_PACKET_SIZE 0.7
-#define HICN_ESTIMATED_LOSSES_ALPHA 0.8
-#define HICN_INTEREST_LIFETIME_REDUCTION_FACTOR 0.8
-
-// other constants
-#define HICN_NANO_IN_A_SEC 1000000000
-#define HICN_MICRO_IN_A_SEC 1000000
-#define HICN_MILLI_IN_A_SEC 1000
-
-namespace transport {
-
-namespace protocol {
-
-enum packetState { sent_, nacked_, received_, timeout1_, timeout2_, lost_ };
-
-typedef enum packetState packetState_t;
-
-struct sentInterest {
- uint64_t transmissionTime;
- uint32_t sequence; // sequence number of the interest sent
- // to handle seq % buffer_size
- packetState_t state; // see packet state
-};
-
-class RTCTransportProtocol : public TransportProtocol,
- public DatagramReassembly {
- public:
- RTCTransportProtocol(implementation::ConsumerSocket *icnet_socket);
-
- ~RTCTransportProtocol();
-
- using TransportProtocol::start;
-
- using TransportProtocol::stop;
-
- void resume() override;
-
- bool verifyKeyPackets() override;
-
- private:
- // algo functions
- void initParams();
- void reset() override;
-
- // 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(Name *interest_name, bool rtx);
- void scheduleNextInterests() override;
- void sentinelTimer();
- void addRetransmissions(uint32_t val);
- void addRetransmissions(uint32_t start, uint32_t stop);
- uint64_t retransmit();
- void checkRtx();
- void probeRtt();
- void newRound();
- void onTimeout(Interest::Ptr &&interest) override;
- bool onNack(const ContentObject &content_object, bool rtx);
- void onContentObject(Interest::Ptr &&interest,
- ContentObject::Ptr &&content_object) override;
- void onPacketDropped(Interest::Ptr &&interest,
- ContentObject::Ptr &&content_object) override {}
- void onReassemblyFailed(std::uint32_t missing_segment) override {}
-
- TRANSPORT_ALWAYS_INLINE virtual void reassemble(
- ContentObject::Ptr &&content_object) override {
- auto read_buffer = content_object->getPayload();
- read_buffer->trimStart(HICN_TIMESTAMP_SIZE);
- Reassembly::read_buffer_ = std::move(read_buffer);
- Reassembly::notifyApplication();
- }
-
- // controller var
- std::unique_ptr<asio::steady_timer> round_timer_;
- unsigned currentState_;
-
- // cwin var
- uint32_t currentCWin_;
- uint32_t maxCWin_;
-
- // names/packets var
- uint32_t actualSegment_;
- uint32_t inflightInterestsCount_;
- // map seq to rtx
- std::map<uint32_t, uint8_t> interestRetransmissions_;
- bool rtx_timer_used_;
- std::unique_ptr<asio::steady_timer> rtx_timer_;
- std::vector<sentInterest> inflightInterests_;
- uint32_t lastSegNacked_; // indicates the segment id in the last received
- // past Nack. we do not ask for retransmissions
- // for samething that is older than this value.
- uint32_t lastReceived_; // segment of the last content object received
- // indicates the base of the window on the client
- uint64_t lastReceivedTime_; // time at which we recevied the
- // lastReceived_ packet
-
- // sentinel
- // if all packets in the window get lost we need something that
- // wakes up our consumer socket. Interest timeouts set to 1 sec
- // expire too late. This timers expire much sooner and if it
- // detects that all the interest in the window may be lost
- // it sends all of them again
- std::unique_ptr<asio::steady_timer> sentinel_timer_;
- uint64_t lastEvent_; // time at which we removed a pending
- // interest from the window
- std::unordered_map<uint32_t, uint8_t> packets_in_window_;
-
- // rtt probes
- // the RTC transport tends to overestimate the RTT
- // du to the production time on the server side
- // once per second we send an interest for wich we know
- // we will get a nack. This nack will keep our estimation
- // close to the reality
- std::unique_ptr<asio::steady_timer> probe_timer_;
- uint64_t time_sent_probe_;
- uint32_t probe_seq_number_;
- bool received_probe_;
-
- uint32_t modMask_;
-
- // stats
- bool firstPckReceived_;
- uint32_t receivedBytes_;
- uint32_t sentInterest_;
- uint32_t receivedData_;
- int32_t packetLost_;
- int32_t lossRecovered_;
- uint32_t firstSequenceInRound_;
- uint32_t highestReceived_;
- double avgPacketSize_;
- bool gotNack_;
- uint32_t gotFutureNack_;
- uint32_t rounds_;
- uint32_t roundsWithoutNacks_;
-
- // we keep track of up two paths (if only one path is in use
- // the two values in the vector will be the same)
- // position 0 stores the path with minRTT
- // position 1 stores the path with maxRTT
- uint32_t producerPathLabels_[2];
-
- std::unordered_map<uint32_t, std::shared_ptr<RTCDataPath>> pathTable_;
- uint32_t roundCounter_;
-
- // CC var
- double estimatedBw_;
- double lossRate_;
- double queuingDelay_;
- unsigned protocolState_;
-
- bool initied;
-};
-
-} // namespace protocol
-
-} // namespace transport
diff --git a/libtransport/src/protocols/rtc/CMakeLists.txt b/libtransport/src/protocols/rtc/CMakeLists.txt
index 77f065d0e..873b345d0 100644
--- a/libtransport/src/protocols/rtc/CMakeLists.txt
+++ b/libtransport/src/protocols/rtc/CMakeLists.txt
@@ -11,27 +11,27 @@
# 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}/probe_handler.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc.h
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.h
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_ldr.h
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_consts.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_indexer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_ldr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_packet.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc.h
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_queue.h
- ${CMAKE_CURRENT_SOURCE_DIR}/probe_handler.h
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_packet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_reassembly.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.h
)
list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/probe_handler.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_ldr.cc
${CMAKE_CURRENT_SOURCE_DIR}/rtc_rc_queue.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/probe_handler.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/rtc_state.cc
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/protocols/rtc/congestion_detection.cc b/libtransport/src/protocols/rtc/congestion_detection.cc
deleted file mode 100644
index e2d44ae66..000000000
--- a/libtransport/src/protocols/rtc/congestion_detection.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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/log.h>
-#include <protocols/rtc/congestion_detection.h>
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-CongestionDetection::CongestionDetection()
- : cc_estimator_(), last_processed_chunk_() {}
-
-CongestionDetection::~CongestionDetection() {}
-
-void CongestionDetection::updateStats() {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- if (chunks_number_.empty()) return;
-
- uint32_t chunk_number = chunks_number_.front();
-
- while (chunks_[chunk_number].getReceivedTime() + HICN_CC_STATS_MAX_DELAY_MS <
- now ||
- chunks_[chunk_number].isComplete()) {
- if (chunk_number == last_processed_chunk_.getFrameSeqNum() + 1) {
- chunks_[chunk_number].setPreviousSentTime(
- last_processed_chunk_.getSentTime());
-
- chunks_[chunk_number].setPreviousReceivedTime(
- last_processed_chunk_.getReceivedTime());
- cc_estimator_.Update(chunks_[chunk_number].getReceivedDelta(),
- chunks_[chunk_number].getSentDelta(),
- chunks_[chunk_number].getSentTime(),
- chunks_[chunk_number].getReceivedTime(),
- chunks_[chunk_number].getFrameSize(), true);
-
- } else {
- TRANSPORT_LOGD(
- "CongestionDetection::updateStats frame %u but not the \
- previous one, last one was %u currentFrame %u",
- chunk_number, last_processed_chunk_.getFrameSeqNum(),
- chunks_[chunk_number].getFrameSeqNum());
- }
-
- last_processed_chunk_ = chunks_[chunk_number];
-
- chunks_.erase(chunk_number);
-
- chunks_number_.pop();
- if (chunks_number_.empty()) break;
-
- chunk_number = chunks_number_.front();
- }
-}
-
-void CongestionDetection::addPacket(const core::ContentObject &content_object) {
- auto payload = content_object.getPayload();
- uint32_t payload_size = (uint32_t)payload->length();
- uint32_t segmentNumber = content_object.getName().getSuffix();
- // uint32_t pkt = segmentNumber & modMask_;
- uint64_t *sentTimePtr = (uint64_t *)payload->data();
-
- // this is just for testing with hiperf, assuming a frame is 10 pkts
- // in the final version, the split should be based on the timestamp in the pkt
- uint32_t frameNum = (int)(segmentNumber / HICN_CC_STATS_CHUNK_SIZE);
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- if (chunks_.find(frameNum) == chunks_.end()) {
- // new chunk of pkts or out of order
- if (last_processed_chunk_.getFrameSeqNum() > frameNum)
- return; // out of order and we already processed the chunk
-
- chunks_[frameNum] = FrameStats(frameNum, HICN_CC_STATS_CHUNK_SIZE);
- chunks_number_.push(frameNum);
- }
-
- chunks_[frameNum].addPacket(*sentTimePtr, now, payload_size);
-}
-
-} // namespace rtc
-} // namespace protocol
-} // namespace transport
diff --git a/libtransport/src/protocols/rtc/congestion_detection.h b/libtransport/src/protocols/rtc/congestion_detection.h
deleted file mode 100644
index 17f4aa54c..000000000
--- a/libtransport/src/protocols/rtc/congestion_detection.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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 <protocols/rtc/trendline_estimator.h>
-
-#include <map>
-#include <queue>
-
-#define HICN_CC_STATS_CHUNK_SIZE 10
-#define HICN_CC_STATS_MAX_DELAY_MS 100
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-class FrameStats {
- public:
- FrameStats()
- : frame_num_(0),
- sent_time_(0),
- received_time_(0),
- previous_sent_time_(0),
- previous_received_time_(0),
- size_(0),
- received_pkt_m(0),
- burst_size_m(HICN_CC_STATS_CHUNK_SIZE){};
-
- FrameStats(uint32_t burst_size)
- : frame_num_(0),
- sent_time_(0),
- received_time_(0),
- previous_sent_time_(0),
- previous_received_time_(0),
- size_(0),
- received_pkt_m(0),
- burst_size_m(burst_size){};
-
- FrameStats(uint32_t frame_num, uint32_t burst_size)
- : frame_num_(frame_num),
- sent_time_(0),
- received_time_(0),
- previous_sent_time_(0),
- previous_received_time_(0),
- size_(0),
- received_pkt_m(0),
- burst_size_m(burst_size){};
-
- FrameStats(uint32_t frame_num, uint64_t sent_time, uint64_t received_time,
- uint32_t size, FrameStats previousFrame, uint32_t burst_size)
- : frame_num_(frame_num),
- sent_time_(sent_time),
- received_time_(received_time),
- previous_sent_time_(previousFrame.getSentTime()),
- previous_received_time_(previousFrame.getReceivedTime()),
- size_(size),
- received_pkt_m(1),
- burst_size_m(burst_size){};
-
- void addPacket(uint64_t sent_time, uint64_t received_time, uint32_t size) {
- size_ += size;
- sent_time_ =
- (sent_time_ == 0) ? sent_time : std::min(sent_time_, sent_time);
- received_time_ = std::max(received_time, received_time_);
- received_pkt_m++;
- }
-
- bool isComplete() { return received_pkt_m == burst_size_m; }
-
- uint32_t getFrameSeqNum() const { return frame_num_; }
- uint64_t getSentTime() const { return sent_time_; }
- uint64_t getReceivedTime() const { return received_time_; }
- uint32_t getFrameSize() const { return size_; }
-
- void setPreviousReceivedTime(uint64_t time) {
- previous_received_time_ = time;
- }
- void setPreviousSentTime(uint64_t time) { previous_sent_time_ = time; }
-
- // todo manage first frame
- double getReceivedDelta() {
- return static_cast<double>(received_time_ - previous_received_time_);
- }
- double getSentDelta() {
- return static_cast<double>(sent_time_ - previous_sent_time_);
- }
-
- private:
- uint32_t frame_num_;
- uint64_t sent_time_;
- uint64_t received_time_;
-
- uint64_t previous_sent_time_;
- uint64_t previous_received_time_;
- uint32_t size_;
-
- uint32_t received_pkt_m;
- uint32_t burst_size_m;
-};
-
-class CongestionDetection {
- public:
- CongestionDetection();
- ~CongestionDetection();
-
- void addPacket(const core::ContentObject &content_object);
-
- BandwidthUsage getState() { return cc_estimator_.State(); }
-
- void updateStats();
-
- private:
- TrendlineEstimator cc_estimator_;
- std::map<uint32_t, FrameStats> chunks_;
- std::queue<uint32_t> chunks_number_;
-
- FrameStats last_processed_chunk_;
-};
-
-} // end namespace rtc
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/probe_handler.cc b/libtransport/src/protocols/rtc/probe_handler.cc
index efba362d4..abaca6ad9 100644
--- a/libtransport/src/protocols/rtc/probe_handler.cc
+++ b/libtransport/src/protocols/rtc/probe_handler.cc
@@ -43,7 +43,7 @@ uint64_t ProbeHandler::getRtt(uint32_t seq) {
std::chrono::steady_clock::now().time_since_epoch())
.count();
uint64_t rtt = now - it->second;
- if(rtt < 1) rtt = 1;
+ if (rtt < 1) rtt = 1;
pending_probes_.erase(it);
diff --git a/libtransport/src/protocols/rtc/probe_handler.h b/libtransport/src/protocols/rtc/probe_handler.h
index b8ed84445..e34b23df0 100644
--- a/libtransport/src/protocols/rtc/probe_handler.h
+++ b/libtransport/src/protocols/rtc/probe_handler.h
@@ -14,9 +14,8 @@
*/
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <functional>
#include <random>
#include <unordered_map>
@@ -32,8 +31,7 @@ class ProbeHandler : public std::enable_shared_from_this<ProbeHandler> {
using SendProbeCallback = std::function<void(uint32_t)>;
public:
- ProbeHandler(SendProbeCallback &&send_callback,
- asio::io_service &io_service);
+ ProbeHandler(SendProbeCallback &&send_callback, asio::io_service &io_service);
~ProbeHandler();
@@ -53,8 +51,8 @@ class ProbeHandler : public std::enable_shared_from_this<ProbeHandler> {
private:
uint32_t probe_interval_; // us
- uint32_t max_probes_; // packets
- uint32_t sent_probes_; // packets
+ uint32_t max_probes_; // packets
+ uint32_t sent_probes_; // packets
std::unique_ptr<asio::steady_timer> probe_timer_;
diff --git a/libtransport/src/protocols/rtc/rtc.cc b/libtransport/src/protocols/rtc/rtc.cc
index 46659ac74..0cb4cda1d 100644
--- a/libtransport/src/protocols/rtc/rtc.cc
+++ b/libtransport/src/protocols/rtc/rtc.cc
@@ -17,8 +17,11 @@
#include <hicn/transport/interfaces/socket_consumer.h>
#include <implementation/socket_consumer.h>
#include <math.h>
+#include <protocols/errors.h>
+#include <protocols/incremental_indexer_bytestream.h>
#include <protocols/rtc/rtc.h>
#include <protocols/rtc/rtc_consts.h>
+#include <protocols/rtc/rtc_indexer.h>
#include <protocols/rtc/rtc_rc_queue.h>
#include <algorithm>
@@ -33,39 +36,41 @@ using namespace interface;
RTCTransportProtocol::RTCTransportProtocol(
implementation::ConsumerSocket *icn_socket)
- : TransportProtocol(icn_socket, nullptr),
- DatagramReassembly(icn_socket, this),
+ : TransportProtocol(icn_socket, new RtcIndexer<>(icn_socket, this),
+ new DatagramReassembly(icn_socket, this)),
number_(0) {
icn_socket->getSocketOption(PORTAL, portal_);
round_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
scheduler_timer_ =
std::make_unique<asio::steady_timer>(portal_->getIoService());
+ pacing_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
}
RTCTransportProtocol::~RTCTransportProtocol() {}
void RTCTransportProtocol::resume() {
- if (is_running_) return;
-
- is_running_ = true;
-
newRound();
+ TransportProtocol::resume();
+}
- portal_->runEventsLoop();
- is_running_ = false;
+std::size_t RTCTransportProtocol::transportHeaderLength() {
+ return DATA_HEADER_SIZE +
+ (fec_decoder_ != nullptr ? fec_decoder_->getFecHeaderSize() : 0);
}
// private
void RTCTransportProtocol::initParams() {
- portal_->setConsumerCallback(this);
+ TransportProtocol::reset();
rc_ = std::make_shared<RTCRateControlQueue>();
ldr_ = std::make_shared<RTCLossDetectionAndRecovery>(
+ indexer_verifier_.get(),
std::bind(&RTCTransportProtocol::sendRtxInterest, this,
std::placeholders::_1),
portal_->getIoService());
state_ = std::make_shared<RTCState>(
+ indexer_verifier_.get(),
std::bind(&RTCTransportProtocol::sendProbeInterest, this,
std::placeholders::_1),
std::bind(&RTCTransportProtocol::discoveredRtt, this),
@@ -83,8 +88,27 @@ void RTCTransportProtocol::initParams() {
// Cancel timer
number_++;
round_timer_->cancel();
+
scheduler_timer_->cancel();
scheduler_timer_on_ = false;
+ last_interest_sent_time_ = 0;
+ last_interest_sent_seq_ = 0;
+
+#if 0
+ if(portal_->isConnectedToFwd()){
+ max_aggregated_interest_ = 1;
+ }else{
+ max_aggregated_interest_ = MAX_INTERESTS_IN_BATCH;
+ }
+#else
+ max_aggregated_interest_ = 1;
+#endif
+
+ max_sent_int_ =
+ std::ceil((double)MAX_PACING_BATCH / (double)max_aggregated_interest_);
+
+ pacing_timer_->cancel();
+ pacing_timer_on_ = false;
// delete all timeouts and future nacks
timeouts_or_nacks_.clear();
@@ -93,16 +117,28 @@ void RTCTransportProtocol::initParams() {
current_sync_win_ = INITIAL_WIN;
max_sync_win_ = INITIAL_WIN_MAX;
- // names/packets var
- next_segment_ = 0;
-
socket_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
RTC_INTEREST_LIFETIME);
+
+ // FEC
+ using namespace std::placeholders;
+ enableFEC(std::bind(&RTCTransportProtocol::onFecPackets, this, _1),
+ /* We leave the buffer allocation to the fec decoder */
+ fec::FECBase::BufferRequested(0));
+
+ if (fec_decoder_) {
+ indexer_verifier_->enableFec(fec_type_);
+ indexer_verifier_->setNFec(0);
+ ldr_->setFecParams(fec::FECUtils::getBlockSymbols(fec_type_),
+ fec::FECUtils::getSourceSymbols(fec_type_));
+ } else {
+ indexer_verifier_->disableFec();
+ }
}
// private
void RTCTransportProtocol::reset() {
- TRANSPORT_LOGD("reset called");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "reset called";
initParams();
newRound();
}
@@ -113,11 +149,13 @@ void RTCTransportProtocol::inactiveProducer() {
current_sync_win_ = INITIAL_WIN;
max_sync_win_ = INITIAL_WIN_MAX;
- TRANSPORT_LOGD("Current window: %u, max_sync_win_: %u", current_sync_win_,
- max_sync_win_);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Current window: " << current_sync_win_
+ << ", max_sync_win_: " << max_sync_win_;
// names/packets var
- next_segment_ = 0;
+ indexer_verifier_->reset();
+ indexer_verifier_->enableFec(fec_type_);
+ indexer_verifier_->setNFec(0);
ldr_->clear();
}
@@ -137,10 +175,13 @@ void RTCTransportProtocol::newRound() {
uint32_t received_bytes = state_->getReceivedBytesInRound();
uint32_t sent_interest = state_->getSentInterestInRound();
uint32_t lost_data = state_->getLostData();
+ uint32_t definitely_lost = state_->getDefinitelyLostPackets();
uint32_t recovered_losses = state_->getRecoveredLosses();
uint32_t received_nacks = state_->getReceivedNacksInRound();
+ uint32_t received_fec = state_->getReceivedFecPackets();
bool in_sync = (current_state_ == SyncState::in_sync);
+ ldr_->onNewRound(in_sync);
state_->onNewRound((double)ROUND_LEN, in_sync);
rc_->onNewRound((double)ROUND_LEN);
@@ -161,11 +202,13 @@ void RTCTransportProtocol::newRound() {
}
}
- TRANSPORT_LOGD("Calling updateSyncWindow in newRound function");
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Calling updateSyncWindow in newRound function";
updateSyncWindow();
sendStatsToApp(sent_retx, received_bytes, sent_interest, lost_data,
- recovered_losses, received_nacks);
+ definitely_lost, recovered_losses, received_nacks,
+ received_fec);
newRound();
});
}
@@ -173,6 +216,7 @@ void RTCTransportProtocol::newRound() {
void RTCTransportProtocol::discoveredRtt() {
start_send_interest_ = true;
ldr_->turnOnRTX();
+ ldr_->onNewRound(false);
updateSyncWindow();
}
@@ -182,22 +226,23 @@ void RTCTransportProtocol::computeMaxSyncWindow() {
if (production_rate == 0.0 || packet_size == 0.0) {
// the consumer has no info about the producer,
// keep the previous maxCWin
- TRANSPORT_LOGD(
- "Returning in computeMaxSyncWindow because: prod_rate: %d || "
- "packet_size: %d",
- (int)(production_rate == 0.0), (int)(packet_size == 0.0));
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Returning in computeMaxSyncWindow because: prod_rate: "
+ << (production_rate == 0.0)
+ << " || packet_size: " << (packet_size == 0.0);
return;
}
+ production_rate += (production_rate * indexer_verifier_->getMaxFecOverhead());
+
uint32_t lifetime = default_values::interest_lifetime;
socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
lifetime);
double lifetime_ms = (double)lifetime / MILLI_IN_A_SEC;
-
- max_sync_win_ =
- (uint32_t)ceil((production_rate * lifetime_ms *
- INTEREST_LIFETIME_REDUCTION_FACTOR) / packet_size);
+ max_sync_win_ = (uint32_t)ceil(
+ (production_rate * lifetime_ms * INTEREST_LIFETIME_REDUCTION_FACTOR) /
+ packet_size);
max_sync_win_ = std::min(max_sync_win_, rc_->getCongesionWindow());
}
@@ -219,12 +264,25 @@ void RTCTransportProtocol::updateSyncWindow() {
// if some of the info are not available do not update the current win
if (prod_rate != 0.0 && rtt != 0.0 && packet_size != 0.0) {
- current_sync_win_ = (uint32_t)ceil(prod_rate * rtt / packet_size);
- current_sync_win_ += (uint32_t)
- ceil(prod_rate * (PRODUCER_BUFFER_MS / MILLI_IN_A_SEC) / packet_size);
+ double fec_interest_overhead = (double)state_->getPendingFecPackets() /
+ (double)(state_->getPendingInterestNumber() -
+ state_->getPendingFecPackets());
+
+ double fec_overhead =
+ std::max(indexer_verifier_->getFecOverhead(), fec_interest_overhead);
+
+ prod_rate += (prod_rate * fec_overhead);
- if(current_state_ == SyncState::catch_up) {
- current_sync_win_ = (uint32_t) (current_sync_win_ * CATCH_UP_WIN_INCREMENT);
+ current_sync_win_ = (uint32_t)ceil(prod_rate * rtt / packet_size);
+ uint32_t buffer = PRODUCER_BUFFER_MS;
+ if (rtt > 150)
+ buffer = buffer * 2; // if the RTT is too large we increase the
+ // the size of the buffer
+ current_sync_win_ +=
+ ceil(prod_rate * (buffer / MILLI_IN_A_SEC) / packet_size);
+
+ if (current_state_ == SyncState::catch_up) {
+ current_sync_win_ = current_sync_win_ * CATCH_UP_WIN_INCREMENT;
}
current_sync_win_ = std::min(current_sync_win_, max_sync_win_);
@@ -243,70 +301,48 @@ void RTCTransportProtocol::decreaseSyncWindow() {
scheduleNextInterests();
}
-void RTCTransportProtocol::sendInterest(Name *interest_name) {
- TRANSPORT_LOGD("Sending interest for name %s",
- interest_name->toString().c_str());
-
- auto interest = core::PacketManager<>::getInstance().getPacket<Interest>();
- interest->setName(*interest_name);
-
- uint32_t lifetime = default_values::interest_lifetime;
- socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
- lifetime);
- interest->setLifetime(uint32_t(lifetime));
-
- if (*on_interest_output_) {
- (*on_interest_output_)(*socket_->getInterface(), *interest);
- }
-
- if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
- return;
- }
-
- portal_->sendInterest(std::move(interest));
-}
-
void RTCTransportProtocol::sendRtxInterest(uint32_t seq) {
- if (!is_running_ && !is_first_) return;
+ if (!isRunning() && !is_first_) return;
- if(!start_send_interest_) return;
+ if (!start_send_interest_) return;
Name *interest_name = nullptr;
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
&interest_name);
- TRANSPORT_LOGD("send rtx %u", seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "send rtx " << seq;
interest_name->setSuffix(seq);
- sendInterest(interest_name);
+ sendInterest(*interest_name);
}
void RTCTransportProtocol::sendProbeInterest(uint32_t seq) {
- if (!is_running_ && !is_first_) return;
+ if (!isRunning() && !is_first_) return;
Name *interest_name = nullptr;
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
&interest_name);
- TRANSPORT_LOGD("send probe %u", seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "send probe " << seq;
interest_name->setSuffix(seq);
- sendInterest(interest_name);
+ sendInterest(*interest_name);
}
void RTCTransportProtocol::scheduleNextInterests() {
- TRANSPORT_LOGD("Schedule next interests");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Schedule next interests";
- if (!is_running_ && !is_first_) return;
+ if (!isRunning() && !is_first_) return;
- if(!start_send_interest_) return; // RTT discovering phase is not finished so
- // do not start to send interests
+ if (pacing_timer_on_) return; // wait pacing timer for the next send
- if (scheduler_timer_on_) return; // wait befor send other interests
+ if (!start_send_interest_)
+ return; // RTT discovering phase is not finished so
+ // do not start to send interests
if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive())) {
- TRANSPORT_LOGD("Inactive producer.");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Inactive producer.";
// here we keep seding the same interest until the producer
// does not start again
- if (next_segment_ != 0) {
+ if (indexer_verifier_->checkNextSuffix() != 0) {
// the producer just become inactive, reset the state
inactiveProducer();
}
@@ -315,125 +351,208 @@ void RTCTransportProtocol::scheduleNextInterests() {
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
&interest_name);
- TRANSPORT_LOGD("send interest %u", next_segment_);
- interest_name->setSuffix(next_segment_);
+ uint32_t next_seg = 0;
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "send interest " << next_seg;
+ interest_name->setSuffix(next_seg);
if (portal_->interestIsPending(*interest_name)) {
// if interest 0 is already pending we return
return;
}
- sendInterest(interest_name);
+ sendInterest(*interest_name);
state_->onSendNewInterest(interest_name);
return;
}
- TRANSPORT_LOGD("Pending interest number: %d -- current_sync_win_: %d",
- state_->getPendingInterestNumber(), current_sync_win_);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Pending interest number: " << state_->getPendingInterestNumber()
+ << " -- current_sync_win_: " << current_sync_win_;
+
+ uint32_t pending = state_->getPendingInterestNumber();
+ if (pending >= current_sync_win_) return; // no space in the window
+
+ if ((current_sync_win_ - pending) < max_aggregated_interest_) {
+ if (scheduler_timer_on_) return; // timer already scheduled
+
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+
+ uint64_t time = now - last_interest_sent_time_;
+ if (time < WAIT_FOR_INTEREST_BATCH) {
+ uint64_t next = WAIT_FOR_INTEREST_BATCH - time;
+ scheduler_timer_on_ = true;
+ scheduler_timer_->expires_from_now(std::chrono::milliseconds(next));
+ scheduler_timer_->async_wait([this](std::error_code ec) {
+ if (ec) return;
+ if (!scheduler_timer_on_) return;
+
+ scheduler_timer_on_ = false;
+ scheduleNextInterests();
+ });
+ return; // whait for the timer
+ }
+ }
+
+ scheduler_timer_on_ = false;
+ scheduler_timer_->cancel();
// skip nacked pacekts
- if (next_segment_ <= state_->getLastSeqNacked()) {
- next_segment_ = state_->getLastSeqNacked() + 1;
+ if (indexer_verifier_->checkNextSuffix() <= state_->getLastSeqNacked()) {
+ indexer_verifier_->jumpToIndex(state_->getLastSeqNacked() + 1);
}
// skipe received packets
- if (next_segment_ <= state_->getHighestSeqReceivedInOrder()) {
- next_segment_ = state_->getHighestSeqReceivedInOrder() + 1;
+ if (indexer_verifier_->checkNextSuffix() <=
+ state_->getHighestSeqReceivedInOrder()) {
+ indexer_verifier_->jumpToIndex(state_->getHighestSeqReceivedInOrder() + 1);
}
uint32_t sent_interests = 0;
+ uint32_t sent_packets = 0;
+ uint32_t aggregated_counter = 0;
+ Name *name = nullptr;
+ Name interest_name;
+ socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
+ std::array<uint32_t, MAX_AGGREGATED_INTEREST> additional_suffixes;
+
while ((state_->getPendingInterestNumber() < current_sync_win_) &&
- (sent_interests < MAX_INTERESTS_IN_BATCH)) {
- TRANSPORT_LOGD("In while loop. Window size: %u", current_sync_win_);
- Name *interest_name = nullptr;
- socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
+ (sent_interests < max_sent_int_)) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "In while loop. Window size: " << current_sync_win_;
+
+ uint32_t next_seg = indexer_verifier_->getNextSuffix();
- interest_name->setSuffix(next_segment_);
+ name->setSuffix(next_seg);
// send the packet only if:
// 1) it is not pending yet (not true for rtx)
// 2) the packet is not received or lost
// 3) is not in the rtx list
- if (portal_->interestIsPending(*interest_name) ||
- state_->isReceivedOrLost(next_segment_) != PacketState::UNKNOWN ||
- ldr_->isRtx(next_segment_)) {
- TRANSPORT_LOGD(
- "skip interest %u because: pending %u, recv %u, rtx %u",
- next_segment_, (portal_->interestIsPending(*interest_name)),
- (state_->isReceivedOrLost(next_segment_) != PacketState::UNKNOWN),
- (ldr_->isRtx(next_segment_)));
- next_segment_ = (next_segment_ + 1) % MIN_PROBE_SEQ;
+ // 4) is fec and is not in order (!= last sent + 1)
+ if (portal_->interestIsPending(*name) ||
+ state_->isReceivedOrLost(next_seg) != PacketState::UNKNOWN ||
+ ldr_->isRtx(next_seg) ||
+ (indexer_verifier_->isFec(next_seg) &&
+ next_seg != last_interest_sent_seq_ + 1)) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "skip interest " << next_seg << " because: pending "
+ << portal_->interestIsPending(*name) << ", recv "
+ << (state_->isReceivedOrLost(next_seg) != PacketState::UNKNOWN)
+ << ", rtx " << (ldr_->isRtx(next_seg)) << ", is old fec "
+ << ((indexer_verifier_->isFec(next_seg) &&
+ next_seg != last_interest_sent_seq_ + 1));
continue;
}
+ if (aggregated_counter == 0) {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "(name) send interest " << next_seg;
+ interest_name = *name;
+ } else {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "(append) send interest " << next_seg;
+ additional_suffixes[aggregated_counter - 1] = next_seg;
+ }
- sent_interests++;
- TRANSPORT_LOGD("send interest %u", next_segment_);
- sendInterest(interest_name);
- state_->onSendNewInterest(interest_name);
+ last_interest_sent_seq_ = next_seg;
+ state_->onSendNewInterest(name);
+ aggregated_counter++;
+
+ if (aggregated_counter >= max_aggregated_interest_) {
+ sent_packets++;
+ sent_interests++;
+ sendInterest(interest_name, &additional_suffixes, aggregated_counter - 1);
+ last_interest_sent_time_ =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ aggregated_counter = 0;
+ }
+ }
- next_segment_ = (next_segment_ + 1) % MIN_PROBE_SEQ;
+ // exiting the while we may have some pending interest to send
+ if (aggregated_counter != 0) {
+ sent_packets++;
+ last_interest_sent_time_ =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ sendInterest(interest_name, &additional_suffixes, aggregated_counter - 1);
}
if (state_->getPendingInterestNumber() < current_sync_win_) {
- // we still have space in the window but we already sent a batch of
- // MAX_INTERESTS_IN_BATCH interest. for the following ones wait one
- // WAIT_BETWEEN_INTEREST_BATCHES to avoid local packets drop
+ // we still have space in the window but we already sent too many packets
+ // wait PACING_WAIT to avoid drops in the kernel
- scheduler_timer_on_ = true;
- scheduler_timer_->expires_from_now(
- std::chrono::microseconds(WAIT_BETWEEN_INTEREST_BATCHES));
+ pacing_timer_on_ = true;
+ pacing_timer_->expires_from_now(std::chrono::microseconds(PACING_WAIT));
scheduler_timer_->async_wait([this](std::error_code ec) {
if (ec) return;
- if (!scheduler_timer_on_) return;
+ if (!pacing_timer_on_) return;
- scheduler_timer_on_ = false;
+ pacing_timer_on_ = false;
scheduleNextInterests();
});
}
}
-void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
- uint32_t segment_number = interest->getName().getSuffix();
-
- TRANSPORT_LOGD("timeout for packet %u", segment_number);
+void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
+ const Name &name) {
+ uint32_t segment_number = name.getSuffix();
if (segment_number >= MIN_PROBE_SEQ) {
// this is a timeout on a probe, do nothing
return;
}
+ PacketState state = state_->isReceivedOrLost(segment_number);
+ if (state != PacketState::UNKNOWN) {
+ // we may recover a packets using fec, ignore this timer
+ return;
+ }
+
timeouts_or_nacks_.insert(segment_number);
if (TRANSPORT_EXPECT_TRUE(state_->isProducerActive()) &&
- segment_number <= state_->getHighestSeqReceivedInOrder()) {
+ segment_number <= state_->getHighestSeqReceived()) {
// we retransmit packets only if the producer is active, otherwise we
// use timeouts to avoid to send too much traffic
//
// a timeout is sent using RTX only if it is an old packet. if it is for a
// seq number that we didn't reach yet, we send the packet using the normal
// schedule next interest
- TRANSPORT_LOGD("handle timeout for packet %u using rtx", segment_number);
- ldr_->onTimeout(segment_number);
- state_->onTimeout(segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "handle timeout for packet " << segment_number << " using rtx";
+ if (ldr_->isRtxOn()) {
+ ldr_->onTimeout(segment_number);
+ if (indexer_verifier_->isFec(segment_number))
+ state_->onTimeout(segment_number, true);
+ else
+ state_->onTimeout(segment_number, false);
+ } else {
+ // in this case we wil never recover the timeout
+ state_->onTimeout(segment_number, true);
+ }
scheduleNextInterests();
return;
}
- TRANSPORT_LOGD("handle timeout for packet %u using normal interests",
- segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "handle timeout for packet " << segment_number
+ << " using normal interests";
- if (segment_number < next_segment_) {
+ if (segment_number < indexer_verifier_->checkNextSuffix()) {
// this is a timeout for a packet that will be generated in the future but
// we are asking for higher sequence numbers. we need to go back like in the
// case of future nacks
- TRANSPORT_LOGD("on timeout next seg = %u, jump to %u",
- next_segment_, segment_number);
- next_segment_ = segment_number;
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "On timeout next seg = " << indexer_verifier_->checkNextSuffix()
+ << ", jump to " << segment_number;
+ // add an extra space in the window
+ current_sync_win_++;
+ indexer_verifier_->jumpToIndex(segment_number);
}
- state_->onTimeout(segment_number);
+ state_->onTimeout(segment_number, false);
scheduleNextInterests();
}
@@ -446,8 +565,8 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) {
// check if the packet got a timeout
- TRANSPORT_LOGD("Nack received %u. Production segment: %u", nack_segment,
- production_seg);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Nack received " << nack_segment
+ << ". Production segment: " << production_seg;
bool compute_stats = true;
auto tn_it = timeouts_or_nacks_.find(nack_segment);
@@ -459,14 +578,15 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) {
state_->onNackPacketReceived(content_object, compute_stats);
ldr_->onNackPacketReceived(content_object);
- // both in case of past and future nack we set next_segment_ equal to the
+ // both in case of past and future nack we jump to the
// production segment in the nack. In case of past nack we will skip unneded
// interest (this is already done in the scheduleNextInterest in any case)
// while in case of future nacks we can go back in time and ask again for the
// content that generated the nack
- TRANSPORT_LOGD("on nack next seg = %u, jump to %u",
- next_segment_, production_seg);
- next_segment_ = production_seg;
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "On nack next seg = " << indexer_verifier_->checkNextSuffix()
+ << ", jump to " << production_seg;
+ indexer_verifier_->jumpToIndex(production_seg);
if (production_seg > nack_segment) {
// remove the nack is it exists
@@ -496,30 +616,33 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) {
void RTCTransportProtocol::onProbe(const ContentObject &content_object) {
bool valid = state_->onProbePacketReceived(content_object);
- if(!valid) return;
+ if (!valid) return;
struct nack_packet_t *probe =
(struct nack_packet_t *)content_object.getPayload()->data();
uint32_t production_seg = probe->getProductionSegement();
- // as for the nacks set next_segment_
- TRANSPORT_LOGD("on probe next seg = %u, jump to %u",
- next_segment_, production_seg);
- next_segment_ = production_seg;
+ // as for the nacks set next_segment
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "on probe next seg = " << indexer_verifier_->checkNextSuffix()
+ << ", jump to " << production_seg;
+ indexer_verifier_->jumpToIndex(production_seg);
ldr_->onProbePacketReceived(content_object);
updateSyncWindow();
}
-void RTCTransportProtocol::onContentObject(Interest &interest,
- ContentObject &content_object) {
- TRANSPORT_LOGD("Received content object of size: %zu",
- content_object.payloadSize());
- uint32_t payload_size = (uint32_t) content_object.payloadSize();
+void RTCTransportProtocol::onContentObjectReceived(
+ Interest &interest, ContentObject &content_object, std::error_code &ec) {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received content object of size: " << content_object.payloadSize();
+ uint32_t payload_size = content_object.payloadSize();
uint32_t segment_number = content_object.getName().getSuffix();
+ ec = make_error_code(protocol_error::not_reassemblable);
+
if (segment_number >= MIN_PROBE_SEQ) {
- TRANSPORT_LOGD("Received probe %u", segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received probe " << segment_number;
if (*on_content_object_input_) {
(*on_content_object_input_)(*socket_->getInterface(), content_object);
}
@@ -528,7 +651,7 @@ void RTCTransportProtocol::onContentObject(Interest &interest,
}
if (payload_size == NACK_HEADER_SIZE) {
- TRANSPORT_LOGD("Received nack %u", segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received nack " << segment_number;
if (*on_content_object_input_) {
(*on_content_object_input_)(*socket_->getInterface(), content_object);
}
@@ -536,9 +659,8 @@ void RTCTransportProtocol::onContentObject(Interest &interest,
return;
}
- TRANSPORT_LOGD("Received content %u", segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received content " << segment_number;
- rc_->onDataPacketReceived(content_object);
bool compute_stats = true;
auto tn_it = timeouts_or_nacks_.find(segment_number);
if (tn_it != timeouts_or_nacks_.end()) {
@@ -551,25 +673,49 @@ void RTCTransportProtocol::onContentObject(Interest &interest,
// check if the packet was already received
PacketState state = state_->isReceivedOrLost(segment_number);
- state_->onDataPacketReceived(content_object, compute_stats);
- ldr_->onDataPacketReceived(content_object);
- // if the stat for this seq number is received do not send the packet to app
if (state != PacketState::RECEIVED) {
- if (*on_content_object_input_) {
- (*on_content_object_input_)(*socket_->getInterface(), content_object);
+ // send packet to decoder
+ if (fec_decoder_) {
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "send packet " << segment_number << " to FEC decoder";
+ fec_decoder_->onDataPacket(
+ content_object, content_object.headerSize() + rtc::DATA_HEADER_SIZE);
+ }
+ if (!indexer_verifier_->isFec(segment_number)) {
+ // the packet may be alredy sent to the ap by the decoder, check again if
+ // it is already received
+ state = state_->isReceivedOrLost(segment_number);
+ if (state != PacketState::RECEIVED) {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Received content " << segment_number;
+
+ state_->onDataPacketReceived(content_object, compute_stats);
+
+ if (*on_content_object_input_) {
+ (*on_content_object_input_)(*socket_->getInterface(), content_object);
+ }
+ ec = make_error_code(protocol_error::success);
+ }
+ } else {
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "Received fec " << segment_number;
+ state_->onFecPacketReceived(content_object);
}
- reassemble(content_object);
} else {
- TRANSPORT_LOGD("Received duplicated content %u, drop it", segment_number);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Received duplicated content " << segment_number << ", drop it";
+ ec = make_error_code(protocol_error::duplicated_content);
}
+ ldr_->onDataPacketReceived(content_object);
+ rc_->onDataPacketReceived(content_object);
+
updateSyncWindow();
}
void RTCTransportProtocol::sendStatsToApp(
uint32_t retx_count, uint32_t received_bytes, uint32_t sent_interests,
- uint32_t lost_data, uint32_t recovered_losses, uint32_t received_nacks) {
+ uint32_t lost_data, uint32_t definitely_lost, uint32_t recovered_losses,
+ uint32_t received_nacks, uint32_t received_fec) {
if (*stats_summary_) {
// Send the stats to the app
stats_->updateQueuingDelay(state_->getQueuing());
@@ -581,23 +727,35 @@ void RTCTransportProtocol::sendStatsToApp(
stats_->updateBytesRecv(received_bytes);
stats_->updateInterestTx(sent_interests);
stats_->updateReceivedNacks(received_nacks);
+ stats_->updateReceivedFEC(received_fec);
stats_->updateAverageWindowSize(current_sync_win_);
stats_->updateLossRatio(state_->getLossRate());
stats_->updateAverageRtt(state_->getRTT());
+ stats_->updateQueuingDelay(state_->getQueuing());
stats_->updateLostData(lost_data);
+ stats_->updateDefinitelyLostData(definitely_lost);
stats_->updateRecoveredData(recovered_losses);
stats_->updateCCState((unsigned int)current_state_ ? 1 : 0);
(*stats_summary_)(*socket_->getInterface(), *stats_);
}
}
-void RTCTransportProtocol::reassemble(ContentObject &content_object) {
- auto read_buffer = content_object.getPayload();
- TRANSPORT_LOGD("Size of payload: %zu", read_buffer->length());
- read_buffer->trimStart(DATA_HEADER_SIZE);
- Reassembly::read_buffer_ = std::move(read_buffer);
- Reassembly::notifyApplication();
+void RTCTransportProtocol::onFecPackets(
+ std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+ for (auto &packet : packets) {
+ PacketState state = state_->isReceivedOrLost(packet.first);
+ if (state != PacketState::RECEIVED) {
+ state_->onPacketRecoveredFec(packet.first);
+ ldr_->onPacketRecoveredFec(packet.first);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Recovered packet " << packet.first << " through FEC.";
+ reassembly_->reassemble(*packet.second, packet.first);
+ } else {
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet" << packet.first << "already received.";
+ }
+ }
}
} // end namespace rtc
diff --git a/libtransport/src/protocols/rtc/rtc.h b/libtransport/src/protocols/rtc/rtc.h
index 596887067..e6431264d 100644
--- a/libtransport/src/protocols/rtc/rtc.h
+++ b/libtransport/src/protocols/rtc/rtc.h
@@ -30,8 +30,7 @@ namespace protocol {
namespace rtc {
-class RTCTransportProtocol : public TransportProtocol,
- public DatagramReassembly {
+class RTCTransportProtocol : public TransportProtocol {
public:
RTCTransportProtocol(implementation::ConsumerSocket *icnet_socket);
@@ -43,6 +42,8 @@ class RTCTransportProtocol : public TransportProtocol,
void resume() override;
+ std::size_t transportHeaderLength() override;
+
private:
enum class SyncState { catch_up = 0, in_sync = 1, last };
@@ -63,24 +64,28 @@ class RTCTransportProtocol : public TransportProtocol,
void decreaseSyncWindow();
// packet functions
- void sendInterest(Name *interest_name);
void sendRtxInterest(uint32_t seq);
void sendProbeInterest(uint32_t seq);
void scheduleNextInterests() override;
- void onTimeout(Interest::Ptr &&interest) override;
+ void onInterestTimeout(Interest::Ptr &interest, const Name &name) override;
void onNack(const ContentObject &content_object);
void onProbe(const ContentObject &content_object);
- void reassemble(ContentObject &content_object) override;
- void onContentObject(Interest &interest,
- ContentObject &content_object) override;
- void onPacketDropped(Interest &interest,
- ContentObject &content_object) override {}
+ void onContentObjectReceived(Interest &interest,
+ ContentObject &content_object,
+ std::error_code &ec) override;
+ void onPacketDropped(Interest &interest, ContentObject &content_object,
+ const std::error_code &reason) override {}
void onReassemblyFailed(std::uint32_t missing_segment) override {}
// interaction with app functions
void sendStatsToApp(uint32_t retx_count, uint32_t received_bytes,
uint32_t sent_interests, uint32_t lost_data,
- uint32_t recovered_losses, uint32_t received_nacks);
+ uint32_t definitely_lost, uint32_t recovered_losses,
+ uint32_t received_nacks, uint32_t received_fec);
+
+ // FEC functions
+ void onFecPackets(std::vector<std::pair<uint32_t, fec::buffer>> &packets);
+
// protocol state
bool start_send_interest_;
SyncState current_state_;
@@ -88,17 +93,30 @@ class RTCTransportProtocol : public TransportProtocol,
uint32_t current_sync_win_;
uint32_t max_sync_win_;
- // controller var
+ // round timer
std::unique_ptr<asio::steady_timer> round_timer_;
+
+ // scheduler timer (postpone interest sending to explot aggregated interests)
std::unique_ptr<asio::steady_timer> scheduler_timer_;
bool scheduler_timer_on_;
+ uint64_t last_interest_sent_time_;
+ uint64_t last_interest_sent_seq_;
+
+ // maximum aggregated interest. if the transport is connected to the forwarder
+ // we cannot use aggregated interests
+ uint32_t max_aggregated_interest_;
+ // maximum number of intereset that can be sent in a loop to avoid packets
+ // dropped by the kernel
+ uint32_t max_sent_int_;
+
+ // pacing timer (do not send too many interests in a short time to avoid
+ // packet drops in the kernel)
+ std::unique_ptr<asio::steady_timer> pacing_timer_;
+ bool pacing_timer_on_;
// timeouts
std::unordered_set<uint32_t> timeouts_or_nacks_;
- // names/packets var
- uint32_t next_segment_;
-
std::shared_ptr<RTCState> state_;
std::shared_ptr<RTCRateControl> rc_;
std::shared_ptr<RTCLossDetectionAndRecovery> ldr_;
diff --git a/libtransport/src/protocols/rtc/rtc_consts.h b/libtransport/src/protocols/rtc/rtc_consts.h
index e172fc7a1..d04bc1b1f 100644
--- a/libtransport/src/protocols/rtc/rtc_consts.h
+++ b/libtransport/src/protocols/rtc/rtc_consts.h
@@ -37,12 +37,26 @@ const double INTEREST_LIFETIME_REDUCTION_FACTOR = 0.8;
const uint32_t PRODUCER_BUFFER_MS = 200; // ms
// interest scheduler
-const uint32_t MAX_INTERESTS_IN_BATCH = 5;
-const uint32_t WAIT_BETWEEN_INTEREST_BATCHES = 1000; // usec
+// const uint32_t MAX_INTERESTS_IN_BATCH = 5;
+// const uint32_t WAIT_BETWEEN_INTEREST_BATCHES = 1000; // usec
+const uint32_t MAX_INTERESTS_IN_BATCH = 5; // number of seq numbers per
+ // aggregated interest packet
+ // considering the name itself
+const uint32_t WAIT_FOR_INTEREST_BATCH = 20; // msec. timer that we wait to try
+ // to aggregate interest in the
+ // same packet
+const uint32_t MAX_PACING_BATCH = 5;
+// number of interest that we can send inside
+// the loop before they get dropped by the
+// kernel.
+const uint32_t PACING_WAIT = 1000; // usec to wait betwing two pacing batch. As
+ // for MAX_PACING_BATCH this value was
+ // computed during tests
+const uint32_t MAX_RTX_IN_BATCH = 10; // max rtx to send in loop
// packet const
const uint32_t HICN_HEADER_SIZE = 40 + 20; // IPv6 + TCP bytes
-const uint32_t RTC_INTEREST_LIFETIME = 1000;
+const uint32_t RTC_INTEREST_LIFETIME = 2000;
// probes sequence range
const uint32_t MIN_PROBE_SEQ = 0xefffffff;
@@ -51,19 +65,18 @@ const uint32_t MAX_RTT_PROBE_SEQ = 0xffffffff - 1;
// RTT_PROBE_INTERVAL will be used during the section while
// INIT_RTT_PROBE_INTERVAL is used at the beginning to
// quickily estimate the RTT
-const uint32_t RTT_PROBE_INTERVAL = 200000; // us
-const uint32_t INIT_RTT_PROBE_INTERVAL = 500; // us
-const uint32_t INIT_RTT_PROBES = 40; // number of probes to init RTT
+const uint32_t RTT_PROBE_INTERVAL = 200000; // us
+const uint32_t INIT_RTT_PROBE_INTERVAL = 500; // us
+const uint32_t INIT_RTT_PROBES = 40; // number of probes to init RTT
// if the produdcer is not yet started we need to probe multple times
// to get an answer. we wait 100ms between each try
-const uint32_t INIT_RTT_PROBE_RESTART = 100; // ms
+const uint32_t INIT_RTT_PROBE_RESTART = 100; // ms
// once we get the first probe we wait at most 60ms for the others
-const uint32_t INIT_RTT_PROBE_WAIT = 30; // ms
+const uint32_t INIT_RTT_PROBE_WAIT = 30; // ms
// we reuires at least 5 probes to be recevied
-const uint32_t INIT_RTT_MIN_PROBES_TO_RECV = 5; //ms
+const uint32_t INIT_RTT_MIN_PROBES_TO_RECV = 5; // ms
const uint32_t MAX_PENDING_PROBES = 10;
-
// congestion
const double MAX_QUEUING_DELAY = 100.0; // ms
@@ -97,7 +110,7 @@ const double MAX_CACHED_PACKETS = 262144; // 2^18
// about 50 sec of traffic at 50Mbps
// with 1200 bytes packets
-const uint32_t MAX_ROUND_WHIOUT_PACKETS = (const uint32_t)
+const uint32_t MAX_ROUND_WHIOUT_PACKETS =
(20 * MILLI_IN_A_SEC) / ROUND_LEN; // 20 sec in rounds;
// used in ldr
diff --git a/libtransport/src/protocols/rtc/rtc_data_path.cc b/libtransport/src/protocols/rtc/rtc_data_path.cc
index a545225cb..c098088a3 100644
--- a/libtransport/src/protocols/rtc/rtc_data_path.cc
+++ b/libtransport/src/protocols/rtc/rtc_data_path.cc
@@ -69,7 +69,7 @@ void RTCDataPath::insertOwdSample(int64_t owd) {
if (avg_owd != DBL_MAX)
avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC);
else {
- avg_owd = (double)owd;
+ avg_owd = owd;
}
int64_t queueVal = owd - std::min(getMinOwd(), min_owd);
@@ -77,7 +77,7 @@ void RTCDataPath::insertOwdSample(int64_t owd) {
if (queuing_delay != DBL_MAX)
queuing_delay = (queuing_delay * (1 - ALPHA_RTC)) + (queueVal * ALPHA_RTC);
else {
- queuing_delay = (double)queueVal;
+ queuing_delay = queueVal;
}
// keep track of the jitter computed as for RTP (RFC 3550)
@@ -100,7 +100,7 @@ void RTCDataPath::computeInterArrivalGap(uint32_t segment_number) {
largest_recv_seq_ = segment_number;
largest_recv_seq_time_ = now;
if (avg_inter_arrival_ == DBL_MAX)
- avg_inter_arrival_ = (double)delta;
+ avg_inter_arrival_ = delta;
else
avg_inter_arrival_ =
(avg_inter_arrival_ * (1 - ALPHA_RTC)) + (delta * ALPHA_RTC);
diff --git a/libtransport/src/protocols/rtc/rtc_indexer.h b/libtransport/src/protocols/rtc/rtc_indexer.h
new file mode 100644
index 000000000..4aee242bb
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_indexer.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 <protocols/errors.h>
+#include <protocols/fec_utils.h>
+#include <protocols/indexer.h>
+#include <protocols/rtc/rtc_consts.h>
+#include <protocols/transport_protocol.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace interface {
+class ConsumerSocket;
+}
+
+namespace protocol {
+
+namespace rtc {
+
+template <uint32_t LIMIT = MIN_PROBE_SEQ>
+class RtcIndexer : public Indexer {
+ public:
+ RtcIndexer(implementation::ConsumerSocket *icn_socket,
+ TransportProtocol *transport)
+ : Indexer(icn_socket, transport),
+ first_suffix_(1),
+ next_suffix_(first_suffix_),
+ fec_type_(fec::FECType::UNKNOWN),
+ n_fec_(0),
+ n_current_fec_(n_fec_) {}
+
+ RtcIndexer(RtcIndexer &&other) : Indexer(std::forward<Indexer>(other)) {}
+
+ ~RtcIndexer() {}
+
+ void reset() override {
+ next_suffix_ = first_suffix_;
+ n_fec_ = 0;
+ }
+
+ uint32_t checkNextSuffix() override { return next_suffix_; }
+
+ uint32_t getNextSuffix() override {
+ if (isFec(next_suffix_)) {
+ if (n_current_fec_) {
+ auto ret = next_suffix_++;
+ n_current_fec_--;
+ return ret;
+ } else {
+ n_current_fec_ = n_fec_;
+ next_suffix_ = nextSource(next_suffix_);
+ }
+ } else if (!n_current_fec_) {
+ n_current_fec_ = n_fec_;
+ }
+
+ return (next_suffix_++ % LIMIT);
+ }
+
+ void setFirstSuffix(uint32_t suffix) override {
+ first_suffix_ = suffix % LIMIT;
+ }
+
+ uint32_t getFirstSuffix() override { return first_suffix_; }
+
+ uint32_t jumpToIndex(uint32_t index) override {
+ next_suffix_ = index % LIMIT;
+ return next_suffix_;
+ }
+
+ void onContentObject(core::Interest &interest,
+ core::ContentObject &content_object,
+ bool reassembly) override {
+ setVerifier();
+ auto ret = verifier_->verifyPackets(&content_object);
+
+ switch (ret) {
+ case auth::VerificationPolicy::ACCEPT: {
+ if (reassembly) {
+ reassembly_->reassemble(content_object);
+ }
+ break;
+ }
+
+ case auth::VerificationPolicy::UNKNOWN:
+ case auth::VerificationPolicy::DROP: {
+ transport_->onPacketDropped(
+ interest, content_object,
+ make_error_code(protocol_error::verification_failed));
+ break;
+ }
+
+ case auth::VerificationPolicy::ABORT: {
+ transport_->onContentReassembled(
+ make_error_code(protocol_error::session_aborted));
+ break;
+ }
+ }
+ }
+
+ /**
+ * Retrieve the next segment to be reassembled.
+ */
+ uint32_t getNextReassemblySegment() override {
+ throw errors::RuntimeException(
+ "Get reassembly segment called on rtc indexer. RTC indexer does not "
+ "provide "
+ "reassembly.");
+ }
+
+ bool isFinalSuffixDiscovered() override { return true; }
+
+ uint32_t getFinalSuffix() override { return LIMIT; }
+
+ void enableFec(fec::FECType fec_type) override { fec_type_ = fec_type; }
+
+ void disableFec() override { fec_type_ = fec::FECType::UNKNOWN; }
+
+ void setNFec(uint32_t n_fec) override {
+ n_fec_ = n_fec;
+ n_current_fec_ = n_fec_;
+ }
+
+ uint32_t getNFec() override { return n_fec_; }
+
+ bool isFec(uint32_t index) override {
+ return isFec(fec_type_, index, first_suffix_);
+ }
+
+ double getFecOverhead() override {
+ if (fec_type_ == fec::FECType::UNKNOWN) {
+ return 0;
+ }
+
+ double k = (double)fec::FECUtils::getSourceSymbols(fec_type_);
+ return (double)n_fec_ / k;
+ }
+
+ double getMaxFecOverhead() override {
+ if (fec_type_ == fec::FECType::UNKNOWN) {
+ return 0;
+ }
+
+ double k = (double)fec::FECUtils::getSourceSymbols(fec_type_);
+ double n = (double)fec::FECUtils::getBlockSymbols(fec_type_);
+ return (double)(n - k) / k;
+ }
+
+ static bool isFec(fec::FECType fec_type, uint32_t index,
+ uint32_t first_suffix) {
+ if (index < LIMIT) {
+ return fec::FECUtils::isFec(fec_type, index, first_suffix);
+ }
+
+ return false;
+ }
+
+ static uint32_t nextSource(fec::FECType fec_type, uint32_t index,
+ uint32_t first_suffix) {
+ return fec::FECUtils::nextSource(fec_type, index, first_suffix) % LIMIT;
+ }
+
+ private:
+ uint32_t nextSource(uint32_t index) {
+ return nextSource(fec_type_, index, first_suffix_);
+ }
+
+ private:
+ uint32_t first_suffix_;
+ uint32_t next_suffix_;
+ fec::FECType fec_type_;
+ bool fec_enabled_;
+ uint32_t n_fec_;
+ uint32_t n_current_fec_;
+};
+
+} // namespace rtc
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_ldr.cc b/libtransport/src/protocols/rtc/rtc_ldr.cc
index 0ef381fe1..f0de48871 100644
--- a/libtransport/src/protocols/rtc/rtc_ldr.cc
+++ b/libtransport/src/protocols/rtc/rtc_ldr.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_ldr.h>
@@ -26,11 +27,13 @@ namespace protocol {
namespace rtc {
RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery(
- SendRtxCallback &&callback, asio::io_service &io_service)
+ Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service)
: rtx_on_(false),
+ fec_on_(false),
next_rtx_timer_(MAX_TIMER_RTX),
last_event_(0),
sentinel_timer_interval_(MAX_TIMER_RTX),
+ indexer_(indexer),
send_rtx_callback_(std::move(callback)) {
timer_ = std::make_unique<asio::steady_timer>(io_service);
sentinel_timer_ = std::make_unique<asio::steady_timer>(io_service);
@@ -40,7 +43,7 @@ RTCLossDetectionAndRecovery::~RTCLossDetectionAndRecovery() {}
void RTCLossDetectionAndRecovery::turnOnRTX() {
rtx_on_ = true;
- scheduleSentinelTimer((uint32_t)(state_->getRTT() * CATCH_UP_RTT_INCREMENT));
+ scheduleSentinelTimer(state_->getRTT() * CATCH_UP_RTT_INCREMENT);
}
void RTCLossDetectionAndRecovery::turnOffRTX() {
@@ -48,6 +51,54 @@ void RTCLossDetectionAndRecovery::turnOffRTX() {
clear();
}
+uint32_t RTCLossDetectionAndRecovery::computeFecPacketsToAsk(bool in_sync) {
+ uint32_t current_fec = indexer_->getNFec();
+ double current_loss_rate = state_->getLossRate();
+ double last_loss_rate = state_->getLastRoundLossRate();
+
+ // when in sync ask for fec only if there are losses for 2 rounds
+ if (in_sync && current_fec == 0 &&
+ (current_loss_rate == 0 || last_loss_rate == 0))
+ return 0;
+
+ double loss_rate = state_->getMaxLossRate() * 1.5;
+
+ if (!in_sync && loss_rate == 0) loss_rate = 0.05;
+ if (loss_rate > 0.5) loss_rate = 0.5;
+
+ double exp_losses = (double)k_ * loss_rate;
+ uint32_t fec_to_ask = ceil(exp_losses / (1 - loss_rate));
+
+ if (fec_to_ask > (n_ - k_)) fec_to_ask = n_ - k_;
+
+ return fec_to_ask;
+}
+
+void RTCLossDetectionAndRecovery::onNewRound(bool in_sync) {
+ uint64_t rtt = state_->getRTT();
+ if (!fec_on_ && rtt >= 100) {
+ // turn on fec, here we may have no info so ask for all packets
+ fec_on_ = true;
+ turnOffRTX();
+ indexer_->setNFec(computeFecPacketsToAsk(in_sync));
+ return;
+ }
+
+ if (fec_on_ && rtt > 80) {
+ // keep using fec, maybe update it
+ indexer_->setNFec(computeFecPacketsToAsk(in_sync));
+ return;
+ }
+
+ if ((fec_on_ && rtt <= 80) || (!rtx_on_ && rtt <= 100)) {
+ // turn on rtx
+ fec_on_ = false;
+ indexer_->setNFec(0);
+ turnOnRTX();
+ return;
+ }
+}
+
void RTCLossDetectionAndRecovery::onTimeout(uint32_t seq) {
// always add timeouts to the RTX list to avoid to send the same packet as if
// it was not a rtx
@@ -55,17 +106,23 @@ void RTCLossDetectionAndRecovery::onTimeout(uint32_t seq) {
last_event_ = getNow();
}
+void RTCLossDetectionAndRecovery::onPacketRecoveredFec(uint32_t seq) {
+ // if an RTX is scheduled for a packet recovered using FEC delete it
+ deleteRtx(seq);
+ recover_with_fec_.erase(seq);
+}
+
void RTCLossDetectionAndRecovery::onDataPacketReceived(
const core::ContentObject &content_object) {
last_event_ = getNow();
uint32_t seq = content_object.getName().getSuffix();
if (deleteRtx(seq)) {
- state_->onPacketRecovered(seq);
+ state_->onPacketRecoveredRtx(seq);
} else {
- if (TRANSPORT_EXPECT_FALSE(!rtx_on_)) return; // do not add if RTX is off
- TRANSPORT_LOGD("received data. add from %u to %u ",
- state_->getHighestSeqReceivedInOrder() + 1, seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "received data. add from "
+ << state_->getHighestSeqReceivedInOrder() + 1 << " to " << seq;
addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1, seq);
}
}
@@ -76,8 +133,6 @@ void RTCLossDetectionAndRecovery::onNackPacketReceived(
uint32_t seq = nack.getName().getSuffix();
- if (TRANSPORT_EXPECT_FALSE(!rtx_on_)) return; // do not add if RTX is off
-
struct nack_packet_t *nack_pkt =
(struct nack_packet_t *)nack.getPayload()->data();
uint32_t production_seq = nack_pkt->getProductionSegement();
@@ -91,8 +146,9 @@ void RTCLossDetectionAndRecovery::onNackPacketReceived(
// productionSeq = 14. 9 is lost but we can try to recover packets 12 13 and
// 14 that are not arrived yet
deleteRtx(seq);
- TRANSPORT_LOGD("received past nack. add from %u to %u ",
- state_->getHighestSeqReceivedInOrder() + 1, production_seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "received past nack. add from "
+ << state_->getHighestSeqReceivedInOrder() + 1
+ << " to " << production_seq;
addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
production_seq);
} else {
@@ -105,8 +161,9 @@ void RTCLossDetectionAndRecovery::onNackPacketReceived(
// with productionSeq = 18. this says that all the packets between 12 and 18
// may got lost and we should ask them
deleteRtx(seq);
- TRANSPORT_LOGD("received futrue nack. add from %u to %u ",
- state_->getHighestSeqReceivedInOrder() + 1, production_seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "received futrue nack. add from "
+ << state_->getHighestSeqReceivedInOrder() + 1
+ << " to " << production_seq;
addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
production_seq);
}
@@ -117,12 +174,13 @@ void RTCLossDetectionAndRecovery::onProbePacketReceived(
// we don't log the reception of a probe packet for the sentinel timer because
// probes are not taken into account into the sync window. we use them as
// future nacks to detect possible packets lost
- if (TRANSPORT_EXPECT_FALSE(!rtx_on_)) return; // do not add if RTX is off
struct nack_packet_t *probe_pkt =
(struct nack_packet_t *)probe.getPayload()->data();
uint32_t production_seq = probe_pkt->getProductionSegement();
- TRANSPORT_LOGD("received probe. add from %u to %u ",
- state_->getHighestSeqReceivedInOrder() + 1, production_seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "received probe. add from "
+ << state_->getHighestSeqReceivedInOrder() + 1 << " to " << production_seq;
+
addToRetransmissions(state_->getHighestSeqReceivedInOrder() + 1,
production_seq);
}
@@ -150,20 +208,41 @@ void RTCLossDetectionAndRecovery::addToRetransmissions(uint32_t start,
}
for (uint32_t seq = start; seq < stop; seq++) {
- if (!isRtx(seq) && // is not already an rtx
- // is not received or lost
- state_->isReceivedOrLost(seq) == PacketState::UNKNOWN) {
- // add rtx
- rtxState state;
- state.first_send_ = state_->getInterestSentTime(seq);
- if (state.first_send_ == 0) // this interest was never sent before
- state.first_send_ = getNow();
- state.next_send_ = computeNextSend(seq, true);
- state.rtx_count_ = 0;
- TRANSPORT_LOGD("add %u to retransmissions. next rtx is %lu ", seq,
- (state.next_send_ - getNow()));
- rtx_state_.insert(std::pair<uint32_t, rtxState>(seq, state));
- rtx_timers_.insert(std::pair<uint64_t, uint32_t>(state.next_send_, seq));
+ if (state_->isReceivedOrLost(seq) == PacketState::UNKNOWN) {
+ if (rtx_on_) {
+ if (!indexer_->isFec(seq)) {
+ // handle it with rtx
+ if (!isRtx(seq)) {
+ state_->onLossDetected(seq);
+ rtxState state;
+ state.first_send_ = state_->getInterestSentTime(seq);
+ if (state.first_send_ == 0) // this interest was never sent before
+ state.first_send_ = getNow();
+ state.next_send_ = computeNextSend(seq, true);
+ state.rtx_count_ = 0;
+ DLOG_IF(INFO, VLOG_IS_ON(4))
+ << "Add " << seq << " to retransmissions. next rtx is %lu "
+ << state.next_send_ - getNow();
+ rtx_state_.insert(std::pair<uint32_t, rtxState>(seq, state));
+ rtx_timers_.insert(
+ std::pair<uint64_t, uint32_t>(state.next_send_, seq));
+ }
+ } else {
+ // is fec, do not send it
+ auto it = recover_with_fec_.find(seq);
+ if (it == recover_with_fec_.end()) {
+ state_->onLossDetected(seq);
+ recover_with_fec_.insert(seq);
+ }
+ }
+ } else {
+ // keep track of losses but recover with FEC
+ auto it = recover_with_fec_.find(seq);
+ if (it == recover_with_fec_.end()) {
+ state_->onLossDetected(seq);
+ recover_with_fec_.insert(seq);
+ }
+ }
}
}
scheduleNextRtx();
@@ -182,13 +261,15 @@ uint64_t RTCLossDetectionAndRecovery::computeNextSend(uint32_t seq,
if (prod_rate != 0) {
double packet_size = state_->getAveragePacketSize();
- estimated_iat = (uint32_t)ceil(1000.0 / (prod_rate / packet_size));
- jitter = (uint32_t)ceil(state_->getJitter());
+ estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
+ jitter = ceil(state_->getJitter());
}
uint32_t wait = estimated_iat + jitter;
- TRANSPORT_LOGD("first rtx for %u in %u ms, rtt = %lu ait = %u jttr = %u",
- seq, wait, state_->getRTT(), estimated_iat, jitter);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "first rtx for " << seq << " in " << wait
+ << " ms, rtt = " << state_->getRTT() << " ait = " << estimated_iat
+ << " jttr = " << jitter;
return now + wait;
} else {
@@ -202,25 +283,26 @@ uint64_t RTCLossDetectionAndRecovery::computeNextSend(uint32_t seq,
}
double packet_size = state_->getAveragePacketSize();
- uint32_t estimated_iat = (uint32_t)ceil(1000.0 / (prod_rate / packet_size));
+ uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
uint64_t rtt = state_->getRTT();
if (rtt == 0) rtt = SENTINEL_TIMER_INTERVAL;
- wait = (uint32_t)rtt;
+ wait = rtt;
if (estimated_iat > rtt) wait = estimated_iat;
- uint32_t jitter = (uint32_t)ceil(state_->getJitter());
+ uint32_t jitter = ceil(state_->getJitter());
wait += jitter;
// it may happen that the channel is congested and we have some additional
// queuing delay to take into account
- uint32_t queue = (uint32_t)ceil(state_->getQueuing());
+ uint32_t queue = ceil(state_->getQueuing());
wait += queue;
- TRANSPORT_LOGD(
- "next rtx for %u in %u ms, rtt = %lu ait = %u jttr = %u queue = %u",
- seq, wait, state_->getRTT(), estimated_iat, jitter, queue);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "next rtx for " << seq << " in " << wait
+ << " ms, rtt = " << state_->getRTT() << " ait = " << estimated_iat
+ << " jttr = " << jitter << " queue = " << queue;
return now + wait;
}
@@ -235,7 +317,7 @@ void RTCLossDetectionAndRecovery::retransmit() {
std::unordered_set<uint32_t> lost_pkt;
uint32_t sent_counter = 0;
while (it != rtx_timers_.end() && it->first <= now &&
- sent_counter < MAX_INTERESTS_IN_BATCH) {
+ sent_counter < MAX_RTX_IN_BATCH) {
uint32_t seq = it->second;
auto rtx_it =
rtx_state_.find(seq); // this should always return a valid iter
@@ -243,11 +325,11 @@ void RTCLossDetectionAndRecovery::retransmit() {
(now - rtx_it->second.first_send_) >= RTC_MAX_AGE ||
seq < state_->getLastSeqNacked()) {
// max rtx reached or packet too old or packet nacked, this packet is lost
- TRANSPORT_LOGD(
- "packet %u lost because 1) max rtx: %u 2) max age: %u 3) naked: %u",
- seq, (rtx_it->second.rtx_count_ >= RTC_MAX_RTX),
- ((now - rtx_it->second.first_send_) >= RTC_MAX_AGE),
- (seq < state_->getLastSeqNacked()));
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "packet " << seq << " lost because 1) max rtx: "
+ << (rtx_it->second.rtx_count_ >= RTC_MAX_RTX) << " 2) max age: "
+ << ((now - rtx_it->second.first_send_) >= RTC_MAX_AGE)
+ << " 3) nacked: " << (seq < state_->getLastSeqNacked());
lost_pkt.insert(seq);
it++;
} else {
@@ -259,8 +341,9 @@ void RTCLossDetectionAndRecovery::retransmit() {
it = rtx_timers_.erase(it);
rtx_timers_.insert(
std::pair<uint64_t, uint32_t>(rtx_it->second.next_send_, seq));
- TRANSPORT_LOGD("send rtx for sequence %u, next send in %lu", seq,
- (rtx_it->second.next_send_ - now));
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "send rtx for sequence " << seq << ", next send in "
+ << (rtx_it->second.next_send_ - now);
send_rtx_callback_(seq);
sent_counter++;
}
@@ -358,20 +441,21 @@ void RTCLossDetectionAndRecovery::sentinelTimer() {
if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive())) {
// this happens at the beginning (or if the producer stops for some
// reason) we need to keep sending interest 0 until we get an answer
- TRANSPORT_LOGD(
- "sentinel timer: the producer is not active, send packet 0");
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "sentinel timer: the producer is not active, send packet 0";
state_->onRetransmission(0);
send_rtx_callback_(0);
} else {
- TRANSPORT_LOGD(
- "sentinel timer: the producer is active, send the 10 oldest packets");
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "sentinel timer: the producer is active, "
+ "send the 10 oldest packets";
sent = true;
uint32_t rtx = 0;
auto it = state_->getPendingInterestsMapBegin();
auto end = state_->getPendingInterestsMapEnd();
while (it != end && rtx < MAX_RTX_WITH_SENTINEL) {
uint32_t seq = it->first;
- TRANSPORT_LOGD("sentinel timer, add %u to the rtx list", seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "sentinel timer, add " << seq << " to the rtx list";
addToRetransmissions(seq, seq + 1);
rtx++;
it++;
@@ -384,36 +468,38 @@ void RTCLossDetectionAndRecovery::sentinelTimer() {
uint32_t next_timer;
double prod_rate = state_->getProducerRate();
if (TRANSPORT_EXPECT_FALSE(!state_->isProducerActive()) || prod_rate == 0) {
- TRANSPORT_LOGD("next timer in %u", SENTINEL_TIMER_INTERVAL);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "next timer in " << SENTINEL_TIMER_INTERVAL;
next_timer = SENTINEL_TIMER_INTERVAL;
} else {
double prod_rate = state_->getProducerRate();
double packet_size = state_->getAveragePacketSize();
- uint32_t estimated_iat = (uint32_t)ceil(1000.0 / (prod_rate / packet_size));
- uint32_t jitter = (uint32_t)ceil(state_->getJitter());
+ uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
+ uint32_t jitter = ceil(state_->getJitter());
// try to reduce the number of timers if the estimated IAT is too small
next_timer = std::max((estimated_iat + jitter) * 20, (uint32_t)1);
- TRANSPORT_LOGD("next sentinel in %u ms, rate: %f, iat: %u, jitter: %u",
- next_timer, ((prod_rate * 8.0) / 1000000.0), estimated_iat,
- jitter);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "next sentinel in " << next_timer
+ << " ms, rate: " << ((prod_rate * 8.0) / 1000000.0)
+ << ", iat: " << estimated_iat << ", jitter: " << jitter;
if (!expired) {
// discount the amout of time that is already passed
- uint32_t discount = (uint32_t)(now - last_event_);
+ uint32_t discount = now - last_event_;
if (next_timer > discount) {
next_timer = next_timer - discount;
} else {
// in this case we trigger the timer in 1 ms
next_timer = 1;
}
- TRANSPORT_LOGD("timer after discout: %u", next_timer);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "timer after discout: " << next_timer;
} else if (sent) {
// wait at least one producer stats interval + owd to check if the
// production rate is reducing.
- uint32_t min_wait = PRODUCER_STATS_INTERVAL + (uint32_t)ceil(state_->getQueuing());
+ uint32_t min_wait = PRODUCER_STATS_INTERVAL + ceil(state_->getQueuing());
next_timer = std::max(next_timer, min_wait);
- TRANSPORT_LOGD("wait for updates from prod, next timer: %u", next_timer);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "wait for updates from prod, next timer: " << next_timer;
}
}
diff --git a/libtransport/src/protocols/rtc/rtc_ldr.h b/libtransport/src/protocols/rtc/rtc_ldr.h
index c0912303b..1b9f9afd6 100644
--- a/libtransport/src/protocols/rtc/rtc_ldr.h
+++ b/libtransport/src/protocols/rtc/rtc_ldr.h
@@ -15,15 +15,16 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/name.h>
+#include <protocols/indexer.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_state.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <functional>
#include <map>
+#include <unordered_map>
namespace transport {
@@ -43,16 +44,23 @@ class RTCLossDetectionAndRecovery
using SendRtxCallback = std::function<void(uint32_t)>;
public:
- RTCLossDetectionAndRecovery(SendRtxCallback &&callback,
+ RTCLossDetectionAndRecovery(Indexer *indexer, SendRtxCallback &&callback,
asio::io_service &io_service);
~RTCLossDetectionAndRecovery();
void setState(std::shared_ptr<RTCState> state) { state_ = state; }
+ void setFecParams(uint32_t n, uint32_t k) {
+ n_ = n;
+ k_ = k;
+ }
void turnOnRTX();
void turnOffRTX();
+ bool isRtxOn() { return rtx_on_; }
+ void onNewRound(bool in_sync);
void onTimeout(uint32_t seq);
+ void onPacketRecoveredFec(uint32_t seq);
void onDataPacketReceived(const core::ContentObject &content_object);
void onNackPacketReceived(const core::ContentObject &nack);
void onProbePacketReceived(const core::ContentObject &probe);
@@ -72,6 +80,7 @@ class RTCLossDetectionAndRecovery
bool deleteRtx(uint32_t seq);
void scheduleSentinelTimer(uint64_t expires_from_now);
void sentinelTimer();
+ uint32_t computeFecPacketsToAsk(bool in_sync);
uint64_t getNow() {
using namespace std::chrono;
@@ -90,14 +99,25 @@ class RTCLossDetectionAndRecovery
// should be sent, and the val is the interest seq number
std::multimap<uint64_t, uint32_t> rtx_timers_;
+ // lost packets that will be recovered with fec
+ std::unordered_set<uint32_t> recover_with_fec_;
+
bool rtx_on_;
+ bool fec_on_;
uint64_t next_rtx_timer_;
uint64_t last_event_;
uint64_t sentinel_timer_interval_;
+
+ // fec params
+ uint32_t n_;
+ uint32_t k_;
+
std::unique_ptr<asio::steady_timer> timer_;
std::unique_ptr<asio::steady_timer> sentinel_timer_;
std::shared_ptr<RTCState> state_;
+ Indexer *indexer_;
+
SendRtxCallback send_rtx_callback_;
};
diff --git a/libtransport/src/protocols/rtc/rtc_packet.h b/libtransport/src/protocols/rtc/rtc_packet.h
index 2f2b19fb9..7dc2f82c3 100644
--- a/libtransport/src/protocols/rtc/rtc_packet.h
+++ b/libtransport/src/protocols/rtc/rtc_packet.h
@@ -90,4 +90,4 @@ struct nack_packet_t {
} // end namespace protocol
-} // end namespace transport \ No newline at end of file
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_frame.cc b/libtransport/src/protocols/rtc/rtc_rc_frame.cc
deleted file mode 100644
index b577b5bea..000000000
--- a/libtransport/src/protocols/rtc/rtc_rc_frame.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <protocols/rtc/rtc_consts.h>
-#include <protocols/rtc/rtc_rc_frame.h>
-
-#include <algorithm>
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-RTCRateControlFrame::RTCRateControlFrame() : cc_detector_() {}
-
-RTCRateControlFrame::~RTCRateControlFrame() {}
-
-void RTCRateControlFrame::onNewRound(double round_len) {
- if (!rc_on_) return;
-
- CongestionState prev_congestion_state = congestion_state_;
- cc_detector_.updateStats();
- congestion_state_ = (CongestionState)cc_detector_.getState();
-
- if (congestion_state_ == CongestionState::Congested) {
- if (prev_congestion_state == CongestionState::Normal) {
- // congestion detected, notify app and init congestion win
- double prod_rate = protocol_state_->getReceivedRate();
- double rtt = (double)protocol_state_->getRTT() / MILLI_IN_A_SEC;
- double packet_size = protocol_state_->getAveragePacketSize();
-
- if (prod_rate == 0.0 || rtt == 0.0 || packet_size == 0.0) {
- // TODO do something
- return;
- }
-
- congestion_win_ = (uint32_t)ceil(prod_rate * rtt / packet_size);
- }
- uint32_t win = congestion_win_ * WIN_DECREASE_FACTOR;
- congestion_win_ = std::max(win, WIN_MIN);
- return;
- }
-}
-
-void RTCRateControlFrame::onDataPacketReceived(
- const core::ContentObject &content_object) {
- if (!rc_on_) return;
-
- uint32_t seq = content_object.getName().getSuffix();
- if (!protocol_state_->isPending(seq)) return;
-
- cc_detector_.addPacket(content_object);
-}
-
-void RTCRateControlFrame::receivedBwProbeTrain(uint64_t firts_probe_ts,
- uint64_t last_probe_ts,
- uint32_t total_probes) {
- // TODO
- return;
-}
-
-} // end namespace rtc
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_frame.h b/libtransport/src/protocols/rtc/rtc_rc_frame.h
deleted file mode 100644
index 25d5ddbb6..000000000
--- a/libtransport/src/protocols/rtc/rtc_rc_frame.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <protocols/rtc/congestion_detection.h>
-#include <protocols/rtc/rtc_rc.h>
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-class RTCRateControlFrame : public RTCRateControl {
- public:
- RTCRateControlFrame();
-
- ~RTCRateControlFrame();
-
- void onNewRound(double round_len);
- void onDataPacketReceived(const core::ContentObject &content_object);
-
- void receivedBwProbeTrain(uint64_t firts_probe_ts, uint64_t last_probe_ts,
- uint32_t total_probes);
-
- private:
- CongestionDetection cc_detector_;
-};
-
-} // end namespace rtc
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_rc_queue.cc b/libtransport/src/protocols/rtc/rtc_rc_queue.cc
index 3c7318dae..a1c89e329 100644
--- a/libtransport/src/protocols/rtc/rtc_rc_queue.cc
+++ b/libtransport/src/protocols/rtc/rtc_rc_queue.cc
@@ -67,11 +67,11 @@ void RTCRateControlQueue::onNewRound(double round_len) {
if (prev_congestion_state == CongestionState::Normal) {
// init the congetion window using the received rate
congestion_win_ = (uint32_t)ceil(received_rate * rtt / packet_size);
- rounds_since_last_drop_ = (uint32_t)ROUNDS_BEFORE_TAKE_ACTION + 1;
+ rounds_since_last_drop_ = ROUNDS_BEFORE_TAKE_ACTION + 1;
}
if (rounds_since_last_drop_ >= ROUNDS_BEFORE_TAKE_ACTION) {
- uint32_t win = congestion_win_ * (uint32_t)WIN_DECREASE_FACTOR;
+ uint32_t win = congestion_win_ * WIN_DECREASE_FACTOR;
congestion_win_ = std::max(win, WIN_MIN);
rounds_since_last_drop_ = 0;
return;
@@ -88,7 +88,7 @@ void RTCRateControlQueue::onNewRound(double round_len) {
rounds_without_congestion_++;
if (rounds_without_congestion_ < ROUNDS_BEFORE_TAKE_ACTION) return;
- congestion_win_ = congestion_win_ * (uint32_t)WIN_INCREASE_FACTOR;
+ congestion_win_ = congestion_win_ * WIN_INCREASE_FACTOR;
congestion_win_ = std::min(congestion_win_, INITIAL_WIN_MAX);
}
}
diff --git a/libtransport/src/protocols/rtc/rtc_reassembly.h b/libtransport/src/protocols/rtc/rtc_reassembly.h
new file mode 100644
index 000000000..15722a6d5
--- /dev/null
+++ b/libtransport/src/protocols/rtc/rtc_reassembly.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 <glog/logging.h>
+#include <protocols/datagram_reassembly.h>
+#include <protocols/rtc/rtc_consts.h>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+class RtcReassembly : public DatagramReassembly {
+ public:
+ RtcReassembly(implementation::ConsumerSocket *icn_socket,
+ TransportProtocol *transport_protocol)
+ : DatagramReassembly(icn_socket, transport_protocol) {}
+
+ void reassemble(core::ContentObject &content_object) override {
+ auto read_buffer = content_object.getPayload();
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Size of payload: " << read_buffer->length();
+ read_buffer->trimStart(transport_protocol_->transportHeaderLength());
+ Reassembly::read_buffer_ = std::move(read_buffer);
+ Reassembly::notifyApplication();
+ }
+};
+
+} // namespace rtc
+} // namespace protocol
+} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/rtc_state.cc b/libtransport/src/protocols/rtc/rtc_state.cc
index 9c965bfed..c99205a26 100644
--- a/libtransport/src/protocols/rtc/rtc_state.cc
+++ b/libtransport/src/protocols/rtc/rtc_state.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_state.h>
@@ -22,11 +23,13 @@ namespace protocol {
namespace rtc {
-RTCState::RTCState(ProbeHandler::SendProbeCallback &&rtt_probes_callback,
+RTCState::RTCState(Indexer *indexer,
+ ProbeHandler::SendProbeCallback &&rtt_probes_callback,
DiscoveredRttCallback &&discovered_rtt_callback,
asio::io_service &io_service)
- : rtt_probes_(std::make_shared<ProbeHandler>(
- std::move(rtt_probes_callback), io_service)),
+ : indexer_(indexer),
+ rtt_probes_(std::make_shared<ProbeHandler>(std::move(rtt_probes_callback),
+ io_service)),
discovered_rtt_callback_(std::move(discovered_rtt_callback)) {
init_rtt_timer_ = std::make_unique<asio::steady_timer>(io_service);
initParams();
@@ -45,14 +48,22 @@ void RTCState::initParams() {
// loss counters
packets_lost_ = 0;
+ definitely_lost_pkt_ = 0;
losses_recovered_ = 0;
first_seq_in_round_ = 0;
highest_seq_received_ = 0;
highest_seq_received_in_order_ = 0;
last_seq_nacked_ = 0;
loss_rate_ = 0.0;
+ avg_loss_rate_ = 0.0;
+ max_loss_rate_ = 0.0;
+ last_round_loss_rate_ = 0.0;
residual_loss_rate_ = 0.0;
+ // fec counters
+ pending_fec_pkt_ = 0;
+ received_fec_pkt_ = 0;
+
// bw counters
received_bytes_ = 0;
avg_packet_size_ = INIT_PACKET_SIZE;
@@ -90,8 +101,14 @@ void RTCState::initParams() {
// pending interests
pending_interests_.clear();
+ // skipped interest
+ last_interest_sent_ = 0;
+ skipped_interests_.clear();
+
// init rtt
- first_interest_sent_ = ~0;
+ first_interest_sent_time_ = ~0;
+ first_interest_sent_seq_ = 0;
+
init_rtt_ = false;
rtt_probes_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
rtt_probes_->sendProbes();
@@ -106,18 +123,51 @@ void RTCState::onSendNewInterest(const core::Name *interest_name) {
uint32_t seq = interest_name->getSuffix();
pending_interests_.insert(std::pair<uint32_t, uint64_t>(seq, now));
- if(sent_interests_ == 0) first_interest_sent_ = now;
+ if (sent_interests_ == 0) {
+ first_interest_sent_time_ = now;
+ first_interest_sent_seq_ = seq;
+ }
+
+ if (indexer_->isFec(seq)) {
+ pending_fec_pkt_++;
+ }
+
+ if (last_interest_sent_ == 0 && seq != 0) {
+ last_interest_sent_ = seq; // init last interest sent
+ }
+
+ // TODO what happen in case of jumps?
+ // look for skipped interests
+ skipped_interests_.erase(seq); // remove seq if it is there
+ for (uint32_t i = last_interest_sent_ + 1; i < seq; i++) {
+ if (indexer_->isFec(i)) {
+ skipped_interests_.insert(i);
+ }
+ }
+
+ last_interest_sent_ = seq;
sent_interests_++;
sent_interests_last_round_++;
}
-void RTCState::onTimeout(uint32_t seq) {
+void RTCState::onTimeout(uint32_t seq, bool lost) {
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) {
pending_interests_.erase(it);
}
received_timeouts_++;
+
+ if (lost) onPacketLost(seq);
+}
+
+void RTCState::onLossDetected(uint32_t seq) {
+ if (!indexer_->isFec(seq)) {
+ packets_lost_++;
+ } else if (skipped_interests_.find(seq) == skipped_interests_.end() &&
+ seq >= first_interest_sent_seq_) {
+ packets_lost_++;
+ }
}
void RTCState::onRetransmission(uint32_t seq) {
@@ -128,7 +178,9 @@ void RTCState::onRetransmission(uint32_t seq) {
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) {
pending_interests_.erase(it);
+#if 0
packets_lost_++;
+#endif
}
sent_rtx_++;
sent_rtx_last_round_++;
@@ -165,6 +217,16 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object,
received_packets_last_round_++;
}
+void RTCState::onFecPacketReceived(const core::ContentObject &content_object) {
+ uint32_t seq = content_object.getName().getSuffix();
+ updateReceivedBytes(content_object);
+ addRecvOrLost(seq, PacketState::RECEIVED);
+ received_fec_pkt_++;
+ // the producer is responding
+ // it is generating valid data packets so we consider it active
+ producer_is_active_ = true;
+}
+
void RTCState::onNackPacketReceived(const core::ContentObject &nack,
bool compute_stats) {
uint32_t seq = nack.getName().getSuffix();
@@ -197,12 +259,14 @@ void RTCState::onNackPacketReceived(const core::ContentObject &nack,
// old nack, seq is lost
// update last nacked
if (last_seq_nacked_ < seq) last_seq_nacked_ = seq;
- TRANSPORT_LOGD("lost packet %u beacuse of a past nack", seq);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "lost packet " << seq << " beacuse of a past nack";
onPacketLost(seq);
} else if (seq > production_seq) {
// future nack
// remove the nack from the pending interest map
// (the packet is not received/lost yet)
+ if (indexer_->isFec(seq)) pending_fec_pkt_--;
pending_interests_.erase(seq);
} else {
// this should be a quite rear event. simply remove the
@@ -221,17 +285,28 @@ void RTCState::onNackPacketReceived(const core::ContentObject &nack,
}
void RTCState::onPacketLost(uint32_t seq) {
- TRANSPORT_LOGD("packet %u is lost", seq);
+#if 0
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "packet " << seq << " is lost";
auto it = pending_interests_.find(seq);
if (it != pending_interests_.end()) {
// this packet was never retransmitted so it does
// not appear in the loss count
packets_lost_++;
}
+#endif
+ if (!indexer_->isFec(seq)) {
+ definitely_lost_pkt_++;
+ DLOG_IF(INFO, VLOG_IS_ON(4)) << "packet " << seq << " is lost";
+ }
addRecvOrLost(seq, PacketState::LOST);
}
-void RTCState::onPacketRecovered(uint32_t seq) {
+void RTCState::onPacketRecoveredRtx(uint32_t seq) {
+ losses_recovered_++;
+ addRecvOrLost(seq, PacketState::RECEIVED);
+}
+
+void RTCState::onPacketRecoveredFec(uint32_t seq) {
losses_recovered_++;
addRecvOrLost(seq, PacketState::RECEIVED);
}
@@ -258,7 +333,6 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
uint32_t production_seq = probe_pkt->getProductionSegement();
uint32_t production_rate = probe_pkt->getProductionRate();
-
if (path_it == path_table_.end()) {
// found a new path
std::shared_ptr<RTCDataPath> newPath =
@@ -298,13 +372,14 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
// wait forever
received_probes_++;
- if(!init_rtt_ && received_probes_ <= INIT_RTT_PROBES){
- if(received_probes_ == 1){
- // we got the first probe, wait at most INIT_RTT_PROBE_WAIT sec for the others
+ if (!init_rtt_ && received_probes_ <= INIT_RTT_PROBES) {
+ if (received_probes_ == 1) {
+ // we got the first probe, wait at most INIT_RTT_PROBE_WAIT sec for the
+ // others
main_path_ = path;
setInitRttTimer(INIT_RTT_PROBE_WAIT);
}
- if(received_probes_ == INIT_RTT_PROBES) {
+ if (received_probes_ == INIT_RTT_PROBES) {
// we are done
init_rtt_timer_->cancel();
checkInitRttTimer();
@@ -314,7 +389,7 @@ bool RTCState::onProbePacketReceived(const core::ContentObject &probe) {
received_packets_last_round_++;
// ignore probes sent before the first interest
- if((now - rtt) <= first_interest_sent_) return false;
+ if ((now - rtt) <= first_interest_sent_time_) return false;
return true;
}
@@ -327,11 +402,11 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
double bytes_per_sec =
((double)received_bytes_ * (MILLI_IN_A_SEC / round_len));
- if(received_rate_ == 0)
+ if (received_rate_ == 0)
received_rate_ = bytes_per_sec;
else
received_rate_ = (received_rate_ * MOVING_AVG_ALPHA) +
- ((1 - MOVING_AVG_ALPHA) * bytes_per_sec);
+ ((1 - MOVING_AVG_ALPHA) * bytes_per_sec);
// search for an active path. There should be only one active path (meaning a
// path that leads to the producer socket -no cache- and from which we are
@@ -354,7 +429,8 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
}
}
- if (in_sync) updateLossRate();
+ // if (in_sync) updateLossRate();
+ updateLossRate();
// handle nacks
if (!nack_on_last_round_ && received_bytes_ > 0) {
@@ -385,6 +461,7 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
// reset counters
received_bytes_ = 0;
packets_lost_ = 0;
+ definitely_lost_pkt_ = 0;
losses_recovered_ = 0;
first_seq_in_round_ = highest_seq_received_;
@@ -397,6 +474,8 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
sent_interests_last_round_ = 0;
sent_rtx_last_round_ = 0;
+ received_fec_pkt_ = 0;
+
rounds_++;
}
@@ -465,6 +544,7 @@ void RTCState::updatePathStats(const core::ContentObject &content_object,
}
void RTCState::updateLossRate() {
+ last_round_loss_rate_ = loss_rate_;
loss_rate_ = 0.0;
residual_loss_rate_ = 0.0;
@@ -475,9 +555,29 @@ void RTCState::updateLossRate() {
// division by 0
if (number_theorically_received_packets_ == 0) return;
+ // XXX this may be quite inefficient if the rate is high
+ // maybe is better to iterate over the set?
+ for (uint32_t i = first_seq_in_round_; i < highest_seq_received_; i++) {
+ auto it = skipped_interests_.find(i);
+ if (it != skipped_interests_.end()) {
+ if (number_theorically_received_packets_ > 0)
+ number_theorically_received_packets_--;
+ skipped_interests_.erase(it);
+ }
+ }
+
loss_rate_ = (double)((double)(packets_lost_) /
(double)number_theorically_received_packets_);
+ if (rounds_ % 15 == 0) max_loss_rate_ = 0; // reset every 3 sec
+ if (loss_rate_ > max_loss_rate_) max_loss_rate_ = loss_rate_;
+
+ if (avg_loss_rate_ == 0)
+ avg_loss_rate_ = loss_rate_;
+ else
+ avg_loss_rate_ =
+ avg_loss_rate_ * MOVING_AVG_ALPHA + loss_rate_ * (1 - MOVING_AVG_ALPHA);
+
residual_loss_rate_ = (double)((double)(packets_lost_ - losses_recovered_) /
(double)number_theorically_received_packets_);
@@ -485,6 +585,10 @@ void RTCState::updateLossRate() {
}
void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
+ if (indexer_->isFec(seq)) {
+ pending_fec_pkt_--;
+ }
+
pending_interests_.erase(seq);
if (received_or_lost_packets_.size() >= MAX_CACHED_PACKETS) {
received_or_lost_packets_.erase(received_or_lost_packets_.begin());
@@ -507,10 +611,12 @@ void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
// 1) there is a gap in the sequence so we do not update largest_in_seq_
// 2) all the packets from largest_in_seq_ to seq are in
// received_or_lost_packets_ an we upate largest_in_seq_
+ // or are FEC packets
for (uint32_t i = highest_seq_received_in_order_ + 1; i <= seq; i++) {
if (received_or_lost_packets_.find(i) ==
- received_or_lost_packets_.end()) {
+ received_or_lost_packets_.end() &&
+ !indexer_->isFec(i)) {
break;
}
// this packet is in order so we can update the
@@ -520,17 +626,17 @@ void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
}
}
-void RTCState::setInitRttTimer(uint32_t wait){
+void RTCState::setInitRttTimer(uint32_t wait) {
init_rtt_timer_->cancel();
init_rtt_timer_->expires_from_now(std::chrono::milliseconds(wait));
init_rtt_timer_->async_wait([this](std::error_code ec) {
- if(ec) return;
+ if (ec) return;
checkInitRttTimer();
});
}
void RTCState::checkInitRttTimer() {
- if(received_probes_ < INIT_RTT_MIN_PROBES_TO_RECV){
+ if (received_probes_ < INIT_RTT_MIN_PROBES_TO_RECV) {
// we didn't received enough probes, restart
received_probes_ = 0;
rtt_probes_->setProbes(INIT_RTT_PROBE_INTERVAL, INIT_RTT_PROBES);
@@ -547,7 +653,7 @@ void RTCState::checkInitRttTimer() {
double prod_rate = getProducerRate();
double rtt = (double)getRTT() / MILLI_IN_A_SEC;
double packet_size = getAveragePacketSize();
- uint32_t pkt_in_rtt_ = (uint32_t)std::floor(((prod_rate / packet_size) * rtt) * 0.8);
+ uint32_t pkt_in_rtt_ = std::floor(((prod_rate / packet_size) * rtt) * 0.8);
last_seq_nacked_ = last_production_seq_ + pkt_in_rtt_;
discovered_rtt_callback_();
diff --git a/libtransport/src/protocols/rtc/rtc_state.h b/libtransport/src/protocols/rtc/rtc_state.h
index e4fefaffe..729ba7a1b 100644
--- a/libtransport/src/protocols/rtc/rtc_state.h
+++ b/libtransport/src/protocols/rtc/rtc_state.h
@@ -15,13 +15,13 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/name.h>
+#include <protocols/indexer.h>
#include <protocols/rtc/probe_handler.h>
#include <protocols/rtc/rtc_data_path.h>
-#include <asio.hpp>
-#include <asio/steady_timer.hpp>
#include <map>
#include <set>
@@ -36,8 +36,10 @@ enum class PacketState : uint8_t { RECEIVED, LOST, UNKNOWN };
class RTCState : std::enable_shared_from_this<RTCState> {
public:
using DiscoveredRttCallback = std::function<void()>;
+
public:
- RTCState(ProbeHandler::SendProbeCallback &&rtt_probes_callback,
+ RTCState(Indexer *indexer,
+ ProbeHandler::SendProbeCallback &&rtt_probes_callback,
DiscoveredRttCallback &&discovered_rtt_callback,
asio::io_service &io_service);
@@ -45,14 +47,17 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// packet events
void onSendNewInterest(const core::Name *interest_name);
- void onTimeout(uint32_t seq);
+ void onTimeout(uint32_t seq, bool lost);
+ void onLossDetected(uint32_t seq);
void onRetransmission(uint32_t seq);
void onDataPacketReceived(const core::ContentObject &content_object,
bool compute_stats);
+ void onFecPacketReceived(const core::ContentObject &content_object);
void onNackPacketReceived(const core::ContentObject &nack,
bool compute_stats);
void onPacketLost(uint32_t seq);
- void onPacketRecovered(uint32_t seq);
+ void onPacketRecoveredRtx(uint32_t seq);
+ void onPacketRecoveredFec(uint32_t seq);
bool onProbePacketReceived(const core::ContentObject &probe);
// protocol state
@@ -65,9 +70,7 @@ class RTCState : std::enable_shared_from_this<RTCState> {
}
// delay metrics
- bool isRttDiscovered() const {
- return init_rtt_;
- }
+ bool isRttDiscovered() const { return init_rtt_; }
uint64_t getRTT() const {
if (mainPathIsValid()) return main_path_->getMinRtt();
@@ -97,13 +100,16 @@ class RTCState : std::enable_shared_from_this<RTCState> {
if (it != pending_interests_.end()) return it->second;
return 0;
}
+
bool isPending(uint32_t seq) {
if (pending_interests_.find(seq) != pending_interests_.end()) return true;
return false;
}
+
uint32_t getPendingInterestNumber() const {
- return (uint32_t)pending_interests_.size();
+ return pending_interests_.size();
}
+
PacketState isReceivedOrLost(uint32_t seq) {
auto it = received_or_lost_packets_.find(seq);
if (it != received_or_lost_packets_.end()) return it->second;
@@ -112,12 +118,25 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// loss rate
double getLossRate() const { return loss_rate_; }
+ double getAvgLossRate() const { return avg_loss_rate_; }
+ double getMaxLossRate() const { return max_loss_rate_; }
+ double getLastRoundLossRate() const { return last_round_loss_rate_; }
double getResidualLossRate() const { return residual_loss_rate_; }
+
+ uint32_t getLostData() const { return packets_lost_; };
+ uint32_t getRecoveredLosses() const { return losses_recovered_; }
+
+ uint32_t getDefinitelyLostPackets() const { return definitely_lost_pkt_; }
+
+ uint32_t getHighestSeqReceived() const { return highest_seq_received_; }
+
uint32_t getHighestSeqReceivedInOrder() const {
return highest_seq_received_in_order_;
}
- uint32_t getLostData() const { return packets_lost_; };
- uint32_t getRecoveredLosses() const { return losses_recovered_; }
+
+ // fec packets
+ uint32_t getReceivedFecPackets() const { return received_fec_pkt_; }
+ uint32_t getPendingFecPackets() const { return pending_fec_pkt_; }
// generic stats
uint32_t getReceivedBytesInRound() const { return received_bytes_; }
@@ -183,11 +202,15 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// loss counters
int32_t packets_lost_;
int32_t losses_recovered_;
+ uint32_t definitely_lost_pkt_;
uint32_t first_seq_in_round_;
uint32_t highest_seq_received_;
uint32_t highest_seq_received_in_order_;
uint32_t last_seq_nacked_; // segment for which we got an oldNack
double loss_rate_;
+ double avg_loss_rate_;
+ double max_loss_rate_;
+ double last_round_loss_rate_;
double residual_loss_rate_;
// bw counters
@@ -211,18 +234,24 @@ class RTCState : std::enable_shared_from_this<RTCState> {
uint32_t sent_interests_last_round_;
uint32_t sent_rtx_last_round_;
+ // fec counter
+ uint32_t received_fec_pkt_;
+ uint32_t pending_fec_pkt_;
+
// round conunters
uint32_t rounds_;
uint32_t rounds_without_nacks_;
uint32_t rounds_without_packets_;
// init rtt
- uint64_t first_interest_sent_;
+ uint64_t first_interest_sent_time_;
+ uint32_t first_interest_sent_seq_;
// producer state
bool
producer_is_active_; // the prodcuer is active if we receive some packets
- uint32_t last_production_seq_; // last production seq received by the producer
+ uint32_t
+ last_production_seq_; // last production seq received by the producer
uint64_t last_prod_update_; // timestamp of the last packets used to update
// stats from the producer
@@ -237,6 +266,13 @@ class RTCState : std::enable_shared_from_this<RTCState> {
// pending interests
std::map<uint32_t, uint64_t> pending_interests_;
+ // indexer
+ Indexer *indexer_;
+
+ // skipped interests
+ uint32_t last_interest_sent_;
+ std::unordered_set<uint32_t> skipped_interests_;
+
// probes
std::shared_ptr<ProbeHandler> rtt_probes_;
bool init_rtt_;
diff --git a/libtransport/src/protocols/rtc/trendline_estimator.cc b/libtransport/src/protocols/rtc/trendline_estimator.cc
deleted file mode 100644
index 7a0803857..000000000
--- a/libtransport/src/protocols/rtc/trendline_estimator.cc
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// FROM
-// https://source.chromium.org/chromium/chromium/src/+/master:third_party/webrtc/modules/congestion_controller/goog_cc/trendline_estimator.cc
-
-#include "trendline_estimator.h"
-
-#include <math.h>
-
-#include <algorithm>
-#include <string>
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-// Parameters for linear least squares fit of regression line to noisy data.
-constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
-constexpr double kDefaultTrendlineThresholdGain = 4.0;
-// const char kBweWindowSizeInPacketsExperiment[] =
-// "WebRTC-BweWindowSizeInPackets";
-
-/*size_t ReadTrendlineFilterWindowSize(
- const WebRtcKeyValueConfig* key_value_config) {
- std::string experiment_string =
- key_value_config->Lookup(kBweWindowSizeInPacketsExperiment);
- size_t window_size;
- int parsed_values =
- sscanf(experiment_string.c_str(), "Enabled-%zu", &window_size);
- if (parsed_values == 1) {
- if (window_size > 1)
- return window_size;
- RTC_LOG(WARNING) << "Window size must be greater than 1.";
- }
- RTC_LOG(LS_WARNING) << "Failed to parse parameters for BweWindowSizeInPackets"
- " experiment from field trial string. Using default.";
- return TrendlineEstimatorSettings::kDefaultTrendlineWindowSize;
-}
-*/
-
-OptionalDouble LinearFitSlope(
- const std::deque<TrendlineEstimator::PacketTiming>& packets) {
- // RTC_DCHECK(packets.size() >= 2);
- // Compute the "center of mass".
- double sum_x = 0;
- double sum_y = 0;
- for (const auto& packet : packets) {
- sum_x += packet.arrival_time_ms;
- sum_y += packet.smoothed_delay_ms;
- }
- double x_avg = sum_x / packets.size();
- double y_avg = sum_y / packets.size();
- // Compute the slope k = \sum (x_i-x_avg)(y_i-y_avg) / \sum (x_i-x_avg)^2
- double numerator = 0;
- double denominator = 0;
- for (const auto& packet : packets) {
- double x = packet.arrival_time_ms;
- double y = packet.smoothed_delay_ms;
- numerator += (x - x_avg) * (y - y_avg);
- denominator += (x - x_avg) * (x - x_avg);
- }
- if (denominator == 0) return OptionalDouble();
- return OptionalDouble(numerator / denominator);
-}
-
-OptionalDouble ComputeSlopeCap(
- const std::deque<TrendlineEstimator::PacketTiming>& packets,
- const TrendlineEstimatorSettings& settings) {
- /*RTC_DCHECK(1 <= settings.beginning_packets &&
- settings.beginning_packets < packets.size());
- RTC_DCHECK(1 <= settings.end_packets &&
- settings.end_packets < packets.size());
- RTC_DCHECK(settings.beginning_packets + settings.end_packets <=
- packets.size());*/
- TrendlineEstimator::PacketTiming early = packets[0];
- for (size_t i = 1; i < settings.beginning_packets; ++i) {
- if (packets[i].raw_delay_ms < early.raw_delay_ms) early = packets[i];
- }
- size_t late_start = packets.size() - settings.end_packets;
- TrendlineEstimator::PacketTiming late = packets[late_start];
- for (size_t i = late_start + 1; i < packets.size(); ++i) {
- if (packets[i].raw_delay_ms < late.raw_delay_ms) late = packets[i];
- }
- if (late.arrival_time_ms - early.arrival_time_ms < 1) {
- return OptionalDouble();
- }
- return OptionalDouble((late.raw_delay_ms - early.raw_delay_ms) /
- (late.arrival_time_ms - early.arrival_time_ms) +
- settings.cap_uncertainty);
-}
-
-constexpr double kMaxAdaptOffsetMs = 15.0;
-constexpr double kOverUsingTimeThreshold = 10;
-constexpr int kMinNumDeltas = 60;
-constexpr int kDeltaCounterMax = 1000;
-
-//} // namespace
-
-constexpr char TrendlineEstimatorSettings::kKey[];
-
-TrendlineEstimatorSettings::TrendlineEstimatorSettings(
- /*const WebRtcKeyValueConfig* key_value_config*/) {
- /*if (absl::StartsWith(
- key_value_config->Lookup(kBweWindowSizeInPacketsExperiment),
- "Enabled")) {
- window_size = ReadTrendlineFilterWindowSize(key_value_config);
- }
- Parser()->Parse(key_value_config->Lookup(TrendlineEstimatorSettings::kKey));*/
- window_size = kDefaultTrendlineWindowSize;
- enable_cap = false;
- beginning_packets = end_packets = 0;
- cap_uncertainty = 0.0;
-
- /*if (window_size < 10 || 200 < window_size) {
- RTC_LOG(LS_WARNING) << "Window size must be between 10 and 200 packets";
- window_size = kDefaultTrendlineWindowSize;
- }
- if (enable_cap) {
- if (beginning_packets < 1 || end_packets < 1 ||
- beginning_packets > window_size || end_packets > window_size) {
- RTC_LOG(LS_WARNING) << "Size of beginning and end must be between 1 and "
- << window_size;
- enable_cap = false;
- beginning_packets = end_packets = 0;
- cap_uncertainty = 0.0;
- }
- if (beginning_packets + end_packets > window_size) {
- RTC_LOG(LS_WARNING)
- << "Size of beginning plus end can't exceed the window size";
- enable_cap = false;
- beginning_packets = end_packets = 0;
- cap_uncertainty = 0.0;
- }
- if (cap_uncertainty < 0.0 || 0.025 < cap_uncertainty) {
- RTC_LOG(LS_WARNING) << "Cap uncertainty must be between 0 and 0.025";
- cap_uncertainty = 0.0;
- }
- }*/
-}
-
-/*std::unique_ptr<StructParametersParser> TrendlineEstimatorSettings::Parser() {
- return StructParametersParser::Create("sort", &enable_sort, //
- "cap", &enable_cap, //
- "beginning_packets",
- &beginning_packets, //
- "end_packets", &end_packets, //
- "cap_uncertainty", &cap_uncertainty, //
- "window_size", &window_size);
-}*/
-
-TrendlineEstimator::TrendlineEstimator(
- /*const WebRtcKeyValueConfig* key_value_config,
- NetworkStatePredictor* network_state_predictor*/)
- : settings_(),
- smoothing_coef_(kDefaultTrendlineSmoothingCoeff),
- threshold_gain_(kDefaultTrendlineThresholdGain),
- num_of_deltas_(0),
- first_arrival_time_ms_(-1),
- accumulated_delay_(0),
- smoothed_delay_(0),
- delay_hist_(),
- k_up_(0.0087),
- k_down_(0.039),
- overusing_time_threshold_(kOverUsingTimeThreshold),
- threshold_(12.5),
- prev_modified_trend_(NAN),
- last_update_ms_(-1),
- prev_trend_(0.0),
- time_over_using_(-1),
- overuse_counter_(0),
- hypothesis_(BandwidthUsage::kBwNormal){
- // hypothesis_predicted_(BandwidthUsage::kBwNormal){//},
- // network_state_predictor_(network_state_predictor) {
- /* RTC_LOG(LS_INFO)
- << "Using Trendline filter for delay change estimation with settings "
- << settings_.Parser()->Encode() << " and "
- // << (network_state_predictor_ ? "injected" : "no")
- << " network state predictor";*/
-}
-
-TrendlineEstimator::~TrendlineEstimator() {}
-
-void TrendlineEstimator::UpdateTrendline(double recv_delta_ms,
- double send_delta_ms,
- int64_t send_time_ms,
- int64_t arrival_time_ms,
- size_t packet_size) {
- const double delta_ms = recv_delta_ms - send_delta_ms;
- ++num_of_deltas_;
- num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax);
- if (first_arrival_time_ms_ == -1) first_arrival_time_ms_ = arrival_time_ms;
-
- // Exponential backoff filter.
- accumulated_delay_ += delta_ms;
- // BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms,
- // accumulated_delay_);
- smoothed_delay_ = smoothing_coef_ * smoothed_delay_ +
- (1 - smoothing_coef_) * accumulated_delay_;
- // BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms,
- // smoothed_delay_);
-
- // Maintain packet window
- delay_hist_.emplace_back(
- static_cast<double>(arrival_time_ms - first_arrival_time_ms_),
- smoothed_delay_, accumulated_delay_);
- if (settings_.enable_sort) {
- for (size_t i = delay_hist_.size() - 1;
- i > 0 &&
- delay_hist_[i].arrival_time_ms < delay_hist_[i - 1].arrival_time_ms;
- --i) {
- std::swap(delay_hist_[i], delay_hist_[i - 1]);
- }
- }
- if (delay_hist_.size() > settings_.window_size) delay_hist_.pop_front();
-
- // Simple linear regression.
- double trend = prev_trend_;
- if (delay_hist_.size() == settings_.window_size) {
- // Update trend_ if it is possible to fit a line to the data. The delay
- // trend can be seen as an estimate of (send_rate - capacity)/capacity.
- // 0 < trend < 1 -> the delay increases, queues are filling up
- // trend == 0 -> the delay does not change
- // trend < 0 -> the delay decreases, queues are being emptied
- OptionalDouble trendO = LinearFitSlope(delay_hist_);
- if (trendO.has_value()) trend = trendO.value();
- if (settings_.enable_cap) {
- OptionalDouble cap = ComputeSlopeCap(delay_hist_, settings_);
- // We only use the cap to filter out overuse detections, not
- // to detect additional underuses.
- if (trend >= 0 && cap.has_value() && trend > cap.value()) {
- trend = cap.value();
- }
- }
- }
- // BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trend);
-
- Detect(trend, send_delta_ms, arrival_time_ms);
-}
-
-void TrendlineEstimator::Update(double recv_delta_ms, double send_delta_ms,
- int64_t send_time_ms, int64_t arrival_time_ms,
- size_t packet_size, bool calculated_deltas) {
- if (calculated_deltas) {
- UpdateTrendline(recv_delta_ms, send_delta_ms, send_time_ms, arrival_time_ms,
- packet_size);
- }
- /*if (network_state_predictor_) {
- hypothesis_predicted_ = network_state_predictor_->Update(
- send_time_ms, arrival_time_ms, hypothesis_);
- }*/
-}
-
-BandwidthUsage TrendlineEstimator::State() const {
- return /*network_state_predictor_ ? hypothesis_predicted_ :*/ hypothesis_;
-}
-
-void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) {
- /*if (num_of_deltas_ < 2) {
- hypothesis_ = BandwidthUsage::kBwNormal;
- return;
- }*/
-
- const double modified_trend =
- std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_;
- prev_modified_trend_ = modified_trend;
- // BWE_TEST_LOGGING_PLOT(1, "T", now_ms, modified_trend);
- // BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
- if (modified_trend > threshold_) {
- if (time_over_using_ == -1) {
- // Initialize the timer. Assume that we've been
- // over-using half of the time since the previous
- // sample.
- time_over_using_ = ts_delta / 2;
- } else {
- // Increment timer
- time_over_using_ += ts_delta;
- }
- overuse_counter_++;
- if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {
- if (trend >= prev_trend_) {
- time_over_using_ = 0;
- overuse_counter_ = 0;
- hypothesis_ = BandwidthUsage::kBwOverusing;
- }
- }
- } else if (modified_trend < -threshold_) {
- time_over_using_ = -1;
- overuse_counter_ = 0;
- hypothesis_ = BandwidthUsage::kBwUnderusing;
- } else {
- time_over_using_ = -1;
- overuse_counter_ = 0;
- hypothesis_ = BandwidthUsage::kBwNormal;
- }
- prev_trend_ = trend;
- UpdateThreshold(modified_trend, now_ms);
-}
-
-void TrendlineEstimator::UpdateThreshold(double modified_trend,
- int64_t now_ms) {
- if (last_update_ms_ == -1) last_update_ms_ = now_ms;
-
- if (fabs(modified_trend) > threshold_ + kMaxAdaptOffsetMs) {
- // Avoid adapting the threshold to big latency spikes, caused e.g.,
- // by a sudden capacity drop.
- last_update_ms_ = now_ms;
- return;
- }
-
- const double k = fabs(modified_trend) < threshold_ ? k_down_ : k_up_;
- const int64_t kMaxTimeDeltaMs = 100;
- int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
- threshold_ += k * (fabs(modified_trend) - threshold_) * time_delta_ms;
- if (threshold_ < 6.f) threshold_ = 6.f;
- if (threshold_ > 600.f) threshold_ = 600.f;
- // threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);
- last_update_ms_ = now_ms;
-}
-
-} // namespace rtc
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/rtc/trendline_estimator.h b/libtransport/src/protocols/rtc/trendline_estimator.h
deleted file mode 100644
index 372acbc67..000000000
--- a/libtransport/src/protocols/rtc/trendline_estimator.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// FROM
-// https://source.chromium.org/chromium/chromium/src/+/master:third_party/webrtc/modules/congestion_controller/goog_cc/trendline_estimator.h
-
-#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_
-#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <deque>
-#include <memory>
-#include <utility>
-
-namespace transport {
-
-namespace protocol {
-
-namespace rtc {
-
-class OptionalDouble {
- public:
- OptionalDouble() : val(0), has_val(false){};
- OptionalDouble(double val) : val(val), has_val(true){};
-
- double value() { return val; }
- bool has_value() { return has_val; }
-
- private:
- double val;
- bool has_val;
-};
-
-enum class BandwidthUsage {
- kBwNormal = 0,
- kBwUnderusing = 1,
- kBwOverusing = 2,
- kLast
-};
-
-struct TrendlineEstimatorSettings {
- static constexpr char kKey[] = "WebRTC-Bwe-TrendlineEstimatorSettings";
- static constexpr unsigned kDefaultTrendlineWindowSize = 20;
-
- // TrendlineEstimatorSettings() = delete;
- TrendlineEstimatorSettings(
- /*const WebRtcKeyValueConfig* key_value_config*/);
-
- // Sort the packets in the window. Should be redundant,
- // but then almost no cost.
- bool enable_sort = false;
-
- // Cap the trendline slope based on the minimum delay seen
- // in the beginning_packets and end_packets respectively.
- bool enable_cap = false;
- unsigned beginning_packets = 7;
- unsigned end_packets = 7;
- double cap_uncertainty = 0.0;
-
- // Size (in packets) of the window.
- unsigned window_size = kDefaultTrendlineWindowSize;
-
- // std::unique_ptr<StructParametersParser> Parser();
-};
-
-class TrendlineEstimator /*: public DelayIncreaseDetectorInterface */ {
- public:
- TrendlineEstimator(/*const WebRtcKeyValueConfig* key_value_config,
- NetworkStatePredictor* network_state_predictor*/);
-
- ~TrendlineEstimator();
-
- // Update the estimator with a new sample. The deltas should represent deltas
- // between timestamp groups as defined by the InterArrival class.
- void Update(double recv_delta_ms, double send_delta_ms, int64_t send_time_ms,
- int64_t arrival_time_ms, size_t packet_size,
- bool calculated_deltas);
-
- void UpdateTrendline(double recv_delta_ms, double send_delta_ms,
- int64_t send_time_ms, int64_t arrival_time_ms,
- size_t packet_size);
-
- BandwidthUsage State() const;
-
- struct PacketTiming {
- PacketTiming(double arrival_time_ms, double smoothed_delay_ms,
- double raw_delay_ms)
- : arrival_time_ms(arrival_time_ms),
- smoothed_delay_ms(smoothed_delay_ms),
- raw_delay_ms(raw_delay_ms) {}
- double arrival_time_ms;
- double smoothed_delay_ms;
- double raw_delay_ms;
- };
-
- private:
- // friend class GoogCcStatePrinter;
- void Detect(double trend, double ts_delta, int64_t now_ms);
-
- void UpdateThreshold(double modified_offset, int64_t now_ms);
-
- // Parameters.
- TrendlineEstimatorSettings settings_;
- const double smoothing_coef_;
- const double threshold_gain_;
- // Used by the existing threshold.
- int num_of_deltas_;
- // Keep the arrival times small by using the change from the first packet.
- int64_t first_arrival_time_ms_;
- // Exponential backoff filtering.
- double accumulated_delay_;
- double smoothed_delay_;
- // Linear least squares regression.
- std::deque<PacketTiming> delay_hist_;
-
- const double k_up_;
- const double k_down_;
- double overusing_time_threshold_;
- double threshold_;
- double prev_modified_trend_;
- int64_t last_update_ms_;
- double prev_trend_;
- double time_over_using_;
- int overuse_counter_;
- BandwidthUsage hypothesis_;
- // BandwidthUsage hypothesis_predicted_;
- // NetworkStatePredictor* network_state_predictor_;
-
- // RTC_DISALLOW_COPY_AND_ASSIGN(TrendlineEstimator);
-};
-
-} // namespace rtc
-
-} // end namespace protocol
-
-} // end namespace transport
-#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_
diff --git a/libtransport/src/protocols/rtc_data_path.cc b/libtransport/src/protocols/rtc_data_path.cc
deleted file mode 100644
index 30644e939..000000000
--- a/libtransport/src/protocols/rtc_data_path.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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 <protocols/rtc_data_path.h>
-
-#include <cfloat>
-#include <chrono>
-
-#define MAX_ROUNDS_WITHOUT_PKTS 10 // 2sec
-
-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(DBL_MAX),
- lastRecvSeq_(0),
- lastRecvTime_(0),
- avg_inter_arrival_(DBL_MAX),
- received_nacks_(false),
- received_packets_(false),
- rounds_without_packets_(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;
-
- if (avg_owd != DBL_MAX)
- avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC);
- else {
- avg_owd = owd;
- }
-
- // owd is computed only for valid data packets so we count only
- // this for decide if we recevie traffic or not
- received_packets_ = true;
-}
-
-void RTCDataPath::computeInterArrivalGap(uint32_t segmentNumber) {
- // got packet in sequence, compute gap
- if (lastRecvSeq_ == (segmentNumber - 1)) {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- uint64_t delta = now - lastRecvTime_;
- lastRecvSeq_ = segmentNumber;
- lastRecvTime_ = now;
- if (avg_inter_arrival_ == DBL_MAX)
- avg_inter_arrival_ = delta;
- else
- avg_inter_arrival_ =
- (avg_inter_arrival_ * (1 - ALPHA_RTC)) + (delta * ALPHA_RTC);
- return;
- }
-
- // ooo packet, update the stasts if needed
- if (lastRecvSeq_ <= segmentNumber) {
- lastRecvSeq_ = segmentNumber;
- lastRecvTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- }
-}
-
-void RTCDataPath::receivedNack() { received_nacks_ = true; }
-
-double RTCDataPath::getInterArrivalGap() {
- if (avg_inter_arrival_ == DBL_MAX) return 0;
- return avg_inter_arrival_;
-}
-
-bool RTCDataPath::isActive() {
- if (received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS)
- return true;
- return false;
-}
-
-void RTCDataPath::roundEnd() {
- // 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;
- }
-
- if (min_rtt == 0) min_rtt = 1;
-
- 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;
- }
-
- if (min_owd != INT_MAX) {
- OWDhistory_.pushBack(min_owd);
- min_owd = INT_MAX;
-
- // compute queuing delay
- queuing_delay = avg_owd - getMinOwd();
-
- } else {
- queuing_delay = 0.0;
- }
-
- if (!received_packets_)
- rounds_without_packets_++;
- else
- rounds_without_packets_ = 0;
- received_packets_ = false;
-}
-
-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/protocols/rtc_data_path.h b/libtransport/src/protocols/rtc_data_path.h
deleted file mode 100644
index 9076b355f..000000000
--- a/libtransport/src/protocols/rtc_data_path.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 <climits>
-
-#include <utils/min_filter.h>
-
-#define ALPHA_RTC 0.125
-#define HISTORY_LEN 20 // 4 sec
-
-namespace transport {
-
-namespace protocol {
-
-class RTCDataPath {
- public:
- RTCDataPath();
-
- public:
- void insertRttSample(uint64_t rtt);
- void insertOwdSample(int64_t owd);
- void computeInterArrivalGap(uint32_t segmentNumber);
- void receivedNack();
-
- uint64_t getMinRtt();
- double getQueuingDealy();
- double getInterArrivalGap();
- bool isActive();
-
- 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;
-
- uint32_t lastRecvSeq_;
- uint64_t lastRecvTime_;
- double avg_inter_arrival_;
-
- // flags to check if a path is active
- // we considere a path active if it reaches a producer
- //(not a cache) --aka we got at least one nack on this path--
- // and if we receives packets
- bool received_nacks_;
- bool received_packets_;
- uint8_t rounds_without_packets_; // if we don't get any packet
- // for MAX_ROUNDS_WITHOUT_PKTS
- // we consider the path inactive
-
- utils::MinFilter<uint64_t> RTThistory_;
- utils::MinFilter<int64_t> OWDhistory_;
-};
-
-} // namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/transport_protocol.cc b/libtransport/src/protocols/transport_protocol.cc
index 611c39212..d6954ac37 100644
--- a/libtransport/src/protocols/transport_protocol.cc
+++ b/libtransport/src/protocols/transport_protocol.cc
@@ -24,12 +24,11 @@ namespace protocol {
using namespace interface;
TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket,
- Reassembly *reassembly_protocol)
+ Indexer *indexer, Reassembly *reassembly)
: socket_(icn_socket),
- reassembly_protocol_(reassembly_protocol),
- index_manager_(
- std::make_unique<IndexManager>(socket_, this, reassembly_protocol)),
- is_running_(false),
+ indexer_verifier_(indexer),
+ reassembly_(reassembly),
+ fec_decoder_(nullptr),
is_first_(false),
on_interest_retransmission_(VOID_HANDLER),
on_interest_output_(VOID_HANDLER),
@@ -37,9 +36,17 @@ TransportProtocol::TransportProtocol(implementation::ConsumerSocket *icn_socket,
on_interest_satisfied_(VOID_HANDLER),
on_content_object_input_(VOID_HANDLER),
stats_summary_(VOID_HANDLER),
- on_payload_(VOID_HANDLER) {
+ on_payload_(VOID_HANDLER),
+ fec_type_(fec::FECType::UNKNOWN),
+ is_running_(false) {
socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
socket_->getSocketOption(OtherOptions::STATISTICS, &stats_);
+
+ // Set this transport protocol as portal's consumer callback
+ portal_->setConsumerCallback(this);
+
+ indexer_verifier_->setReassembly(reassembly_.get());
+ reassembly->setIndexer(indexer_verifier_.get());
}
int TransportProtocol::start() {
@@ -69,6 +76,7 @@ int TransportProtocol::start() {
// Reset the protocol state machine
reset();
+
// Schedule next interests
scheduleNextInterests();
@@ -99,15 +107,27 @@ void TransportProtocol::stop() {
}
void TransportProtocol::resume() {
- if (is_running_) return;
+ if (isRunning()) return;
is_running_ = true;
scheduleNextInterests();
- portal_->runEventsLoop();
+ if (!is_async_) {
+ // Start Event loop
+ portal_->runEventsLoop();
- is_running_ = false;
+ // Not running anymore
+ is_running_ = false;
+ }
+}
+
+void TransportProtocol::reset() {
+ reassembly_->reInitialize();
+ indexer_verifier_->reset();
+ if (fec_decoder_) {
+ fec_decoder_->reset();
+ }
}
void TransportProtocol::onContentReassembled(std::error_code ec) {
@@ -127,6 +147,70 @@ void TransportProtocol::onContentReassembled(std::error_code ec) {
}
}
+void TransportProtocol::sendInterest(
+ const Name &interest_name,
+ std::array<uint32_t, MAX_AGGREGATED_INTEREST> *additional_suffixes,
+ uint32_t len) {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending interest for name " << interest_name;
+
+ auto interest = core::PacketManager<>::getInstance().getPacket<Interest>();
+ interest->setName(interest_name);
+
+ for (uint32_t i = 0; i < len; i++) {
+ interest->appendSuffix(additional_suffixes->at(i));
+ }
+
+ uint32_t lifetime = default_values::interest_lifetime;
+ socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+ lifetime);
+ interest->setLifetime(uint32_t(lifetime));
+
+ if (*on_interest_output_) {
+ (*on_interest_output_)(*socket_->getInterface(), *interest);
+ }
+
+ if (TRANSPORT_EXPECT_FALSE(!isRunning() && !is_first_)) {
+ return;
+ }
+
+ portal_->sendInterest(std::move(interest));
+}
+
+void TransportProtocol::onTimeout(Interest::Ptr &i, const Name &n) {
+ if (TRANSPORT_EXPECT_FALSE(!isRunning())) {
+ return;
+ }
+
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Timeout on content " << n;
+
+ onInterestTimeout(i, n);
+}
+
+void TransportProtocol::onContentObject(Interest &i, ContentObject &c) {
+ // Check whether it makes sense to continue
+ if (TRANSPORT_EXPECT_FALSE(!isRunning())) {
+ return;
+ }
+
+ // Call transport protocol function
+ std::error_code ec;
+ onContentObjectReceived(i, c, ec);
+
+ // Call reassemble function, if packet is eligible for reassemblying
+ bool reassemble = false;
+ if (!ec) {
+ reassemble = true;
+ }
+
+ // Perform verification and update indexer. This step may be performed offline
+ // - i.e. we may not get a result here (e.g. we use manifest). Verification
+ // failures in that case will be handled in the onPacketDropped function.
+ // XXX This step should be done before calling onContentObjectReceived, but
+ // for now we do it here since currently the indexer does not need manifests
+ // to move forward.
+ indexer_verifier_->onContentObject(i, c, reassemble);
+}
+
} // end namespace protocol
} // end namespace transport
diff --git a/libtransport/src/protocols/transport_protocol.h b/libtransport/src/protocols/transport_protocol.h
index 124c57122..1008a238b 100644
--- a/libtransport/src/protocols/transport_protocol.h
+++ b/libtransport/src/protocols/transport_protocol.h
@@ -21,9 +21,11 @@
#include <hicn/transport/utils/object_pool.h>
#include <implementation/socket.h>
#include <protocols/data_processing_events.h>
+#include <protocols/fec_base.h>
#include <protocols/indexer.h>
#include <protocols/reassembly.h>
+#include <array>
#include <atomic>
namespace transport {
@@ -36,12 +38,6 @@ class IndexVerificationManager;
using ReadCallback = interface::ConsumerSocket::ReadCallback;
-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 core::Portal::ConsumerCallback,
public ContentObjectProcessingEventCallback {
static constexpr std::size_t interest_pool_size = 4096;
@@ -50,7 +46,7 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
public:
TransportProtocol(implementation::ConsumerSocket *icn_socket,
- Reassembly *reassembly_protocol);
+ Indexer *indexer, Reassembly *reassembly);
virtual ~TransportProtocol() = default;
@@ -62,27 +58,70 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
virtual void resume();
+ /**
+ * @brief Get the size of any additional header added by the specific
+ * transport implementation.
+ *
+ * @return The header length in bytes.
+ */
+ virtual std::size_t transportHeaderLength() { return 0; }
+
virtual void scheduleNextInterests() = 0;
// Events generated by the indexing
virtual void onContentReassembled(std::error_code ec);
virtual void onPacketDropped(Interest &interest,
- ContentObject &content_object) override = 0;
+ ContentObject &content_object,
+ const std::error_code &ec) override = 0;
virtual void onReassemblyFailed(std::uint32_t missing_segment) override = 0;
protected:
+ virtual void onContentObjectReceived(Interest &i, ContentObject &c,
+ std::error_code &ec) = 0;
+ virtual void onInterestTimeout(Interest::Ptr &i, const Name &n) = 0;
+
+ virtual void sendInterest(const Name &interest_name,
+ std::array<uint32_t, MAX_AGGREGATED_INTEREST>
+ *additional_suffixes = nullptr,
+ uint32_t len = 0);
+
+ template <typename FECHandler, typename AllocatorHandler>
+ void enableFEC(FECHandler &&fec_handler,
+ AllocatorHandler &&allocator_handler) {
+ if (!fec_decoder_) {
+ // Try to get FEC from environment
+ if (const char *fec_str = std::getenv("TRANSPORT_FEC_TYPE")) {
+ LOG(INFO) << "Using FEC " << fec_str;
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str);
+ }
+
+ if (fec_type_ == fec::FECType::UNKNOWN) {
+ return;
+ }
+
+ fec_decoder_ = fec::FECUtils::getDecoder(
+ fec_type_, indexer_verifier_->getFirstSuffix());
+ fec_decoder_->setFECCallback(std::forward<FECHandler>(fec_handler));
+ fec_decoder_->setBufferCallback(
+ std::forward<AllocatorHandler>(allocator_handler));
+ indexer_verifier_->enableFec(fec_type_);
+ }
+ }
+
+ virtual void reset();
+
+ private:
// Consumer Callback
- virtual void reset() = 0;
- virtual void onContentObject(Interest &i, ContentObject &c) override = 0;
- virtual void onTimeout(Interest::Ptr &&i) override = 0;
- virtual void onError(std::error_code ec) override {}
+ void onContentObject(Interest &i, ContentObject &c) override;
+ void onTimeout(Interest::Ptr &i, const Name &n) override;
+ void onError(std::error_code ec) override {}
protected:
implementation::ConsumerSocket *socket_;
- std::unique_ptr<Reassembly> reassembly_protocol_;
- std::unique_ptr<IndexManager> index_manager_;
+ std::unique_ptr<Indexer> indexer_verifier_;
+ std::unique_ptr<Reassembly> reassembly_;
+ std::unique_ptr<fec::ConsumerFEC> fec_decoder_;
std::shared_ptr<core::Portal> portal_;
- std::atomic<bool> is_running_;
// True if it si the first time we schedule an interest
std::atomic<bool> is_first_;
interface::TransportStatistics *stats_;
@@ -98,6 +137,11 @@ class TransportProtocol : public core::Portal::ConsumerCallback,
ReadCallback *on_payload_;
bool is_async_;
+
+ fec::FECType fec_type_;
+
+ private:
+ std::atomic<bool> is_running_;
};
} // end namespace protocol
diff --git a/libtransport/src/protocols/verification_manager.cc b/libtransport/src/protocols/verification_manager.cc
deleted file mode 100644
index 8eedd6106..000000000
--- a/libtransport/src/protocols/verification_manager.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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/security/verifier.h>
-
-#include <implementation/socket_consumer.h>
-#include <protocols/verification_manager.h>
-
-namespace transport {
-
-namespace protocol {
-
-interface::VerificationPolicy SignatureVerificationManager::onPacketToVerify(
- const Packet& packet) {
- using namespace interface;
-
- bool verify_signature = false, key_content = false;
- VerificationPolicy ret = VerificationPolicy::DROP_PACKET;
-
- icn_socket_->getSocketOption(GeneralTransportOptions::VERIFY_SIGNATURE,
- verify_signature);
- icn_socket_->getSocketOption(GeneralTransportOptions::KEY_CONTENT,
- key_content);
-
- if (!verify_signature) {
- return VerificationPolicy::ACCEPT_PACKET;
- }
-
- if (key_content) {
- key_packets_.push(copyPacket(packet));
- return VerificationPolicy::ACCEPT_PACKET;
- } else if (!key_packets_.empty()) {
- std::queue<ContentObjectPtr>().swap(key_packets_);
- }
-
- ConsumerContentObjectVerificationFailedCallback*
- verification_failed_callback = VOID_HANDLER;
- icn_socket_->getSocketOption(ConsumerCallbacksOptions::VERIFICATION_FAILED,
- &verification_failed_callback);
-
- if (!verification_failed_callback) {
- throw errors::RuntimeException(
- "No verification failed callback provided by application. "
- "Aborting.");
- }
-
- std::shared_ptr<utils::Verifier> verifier;
- icn_socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier);
-
- if (TRANSPORT_EXPECT_FALSE(!verifier)) {
- ret = (*verification_failed_callback)(
- *icn_socket_->getInterface(),
- dynamic_cast<const ContentObject&>(packet),
- make_error_code(protocol_error::no_verifier_provided));
- return ret;
- }
-
- if (!verifier->verify(packet)) {
- ret = (*verification_failed_callback)(
- *icn_socket_->getInterface(),
- dynamic_cast<const ContentObject&>(packet),
- make_error_code(protocol_error::signature_verification_failed));
- } else {
- ret = VerificationPolicy::ACCEPT_PACKET;
- }
-
- return ret;
-}
-
-bool SignatureVerificationManager::onKeyToVerify() {
- if (TRANSPORT_EXPECT_FALSE(key_packets_.empty())) {
- throw errors::RuntimeException("No key to verify.");
- }
-
- while (!key_packets_.empty()) {
- ContentObjectPtr packet_to_verify = key_packets_.front();
- key_packets_.pop();
- if (onPacketToVerify(*packet_to_verify) !=
- VerificationPolicy::ACCEPT_PACKET)
- return false;
- }
-
- return true;
-}
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/protocols/verification_manager.h b/libtransport/src/protocols/verification_manager.h
deleted file mode 100644
index 7d8a00a65..000000000
--- a/libtransport/src/protocols/verification_manager.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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/callbacks.h>
-#include <hicn/transport/interfaces/verification_policy.h>
-
-#include <hicn/transport/core/content_object.h>
-
-#include <protocols/errors.h>
-
-#include <queue>
-
-namespace transport {
-
-namespace interface {
-class ConsumerSocket;
-}
-
-namespace protocol {
-
-using Packet = core::Packet;
-using interface::VerificationPolicy;
-using ContentObjectPtr = std::shared_ptr<core::ContentObject>;
-
-class VerificationManager {
- public:
- virtual ~VerificationManager() = default;
- virtual VerificationPolicy onPacketToVerify(const Packet& packet) = 0;
- virtual bool onKeyToVerify() { return false; }
-};
-
-class SignatureVerificationManager : public VerificationManager {
- public:
- SignatureVerificationManager(implementation::ConsumerSocket* icn_socket)
- : icn_socket_(icn_socket), key_packets_() {}
-
- interface::VerificationPolicy onPacketToVerify(const Packet& packet) override;
- bool onKeyToVerify() override;
-
- private:
- implementation::ConsumerSocket* icn_socket_;
- std::queue<ContentObjectPtr> key_packets_;
-
- ContentObjectPtr copyPacket(const Packet& packet) {
- std::shared_ptr<utils::MemBuf> packet_copy =
- packet.acquireMemBufReference();
- ContentObjectPtr content_object_copy =
- std::make_shared<core::ContentObject>(std::move(packet_copy));
- std::unique_ptr<utils::MemBuf> payload_copy = packet.getPayload();
- content_object_copy->appendPayload(std::move(payload_copy));
- return content_object_copy;
- }
-};
-
-} // end namespace protocol
-
-} // end namespace transport
diff --git a/libtransport/src/security/identity.cc b/libtransport/src/security/identity.cc
deleted file mode 100644
index d7a08f7b5..000000000
--- a/libtransport/src/security/identity.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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/security/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, suite);
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
-}
-
-Identity::Identity(const Identity &other)
- : signer_(other.signer_), hash_algorithm_(other.hash_algorithm_) {
- 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,
- (unsigned int)key_length, validity_days, subject_name);
-}
-
-Identity::Identity(std::string &file_name, std::string &password,
- utils::CryptoHashType 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, CryptoSuite(parcSigner_GetCryptoSuite(signer)));
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
-}
-
-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_));
-}
-
-std::shared_ptr<Signer> Identity::getSigner() { return signer_; }
-
-size_t Identity::getSignatureLength() const {
- return signer_->getSignatureLength();
-}
-
-} // namespace utils
diff --git a/libtransport/src/security/signer.cc b/libtransport/src/security/signer.cc
deleted file mode 100644
index aa2751611..000000000
--- a/libtransport/src/security/signer.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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/security/key_id.h>
-#include <hicn/transport/security/signer.h>
-#include <hicn/transport/utils/membuf.h>
-
-extern "C" {
-#ifndef _WIN32
-TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
-#endif
-#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 {
-
-Signer::Signer(PARCKeyStore *keyStore, CryptoSuite suite) {
- parcSecurity_Init();
-
- switch (suite) {
- case CryptoSuite::DSA_SHA256:
- case CryptoSuite::RSA_SHA256:
- case CryptoSuite::RSA_SHA512:
- case CryptoSuite::ECDSA_256K1: {
- this->signer_ =
- parcSigner_Create(parcPublicKeySigner_Create(
- keyStore, static_cast<PARCCryptoSuite>(suite)),
- PARCPublicKeySignerAsSigner);
- break;
- }
- case CryptoSuite::HMAC_SHA256:
- case CryptoSuite::HMAC_SHA512: {
- this->signer_ =
- parcSigner_Create(parcSymmetricKeySigner_Create(
- (PARCSymmetricKeyStore *)keyStore,
- parcCryptoSuite_GetCryptoHash(
- static_cast<PARCCryptoSuite>(suite))),
- PARCSymmetricKeySignerAsSigner);
- break;
- }
- default: { return; }
- }
-
- suite_ = suite;
- key_id_ = parcSigner_CreateKeyId(this->signer_);
- signature_length_ = parcSigner_GetSignatureSize(this->signer_);
-}
-
-Signer::Signer(const std::string &passphrase, CryptoSuite suite) {
- parcSecurity_Init();
-
- switch (suite) {
- case CryptoSuite::HMAC_SHA256:
- case CryptoSuite::HMAC_SHA512: {
- PARCBufferComposer *composer = parcBufferComposer_Create();
- parcBufferComposer_PutString(composer, passphrase.c_str());
- PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
- PARCSymmetricKeyStore *symmetricKeyStore =
- parcSymmetricKeyStore_Create(key_buffer);
- this->signer_ = parcSigner_Create(
- parcSymmetricKeySigner_Create(
- symmetricKeyStore, parcCryptoSuite_GetCryptoHash(
- static_cast<PARCCryptoSuite>(suite))),
- PARCSymmetricKeySignerAsSigner);
-
- parcBuffer_Release(&key_buffer);
- parcSymmetricKeyStore_Release(&symmetricKeyStore);
- parcBufferComposer_Release(&composer);
- break;
- }
- default: { return; }
- }
-
- suite_ = suite;
- key_id_ = parcSigner_CreateKeyId(this->signer_);
- signature_length_ = parcSigner_GetSignatureSize(this->signer_);
-}
-
-Signer::Signer(const PARCSigner *signer, CryptoSuite suite)
- : suite_(suite),
- signer_(parcSigner_Acquire(signer)),
- key_id_(parcSigner_CreateKeyId(this->signer_)),
- signature_length_(parcSigner_GetSignatureSize(this->signer_)) {
- parcSecurity_Init();
-}
-
-Signer::Signer(const PARCSigner *signer)
- : Signer(signer, CryptoSuite::UNKNOWN) {}
-
-Signer::~Signer() {
- if (signer_) parcSigner_Release(&signer_);
- if (key_id_) parcKeyId_Release(&key_id_);
- parcSecurity_Fini();
-}
-
-void Signer::sign(Packet &packet) {
- /* header chain points to the IP + TCP hicn header + AH Header */
- MemBuf *header_chain = packet.header_head_;
- MemBuf *payload_chain = packet.payload_head_;
- uint8_t *hicn_packet = (uint8_t *)header_chain->writableData();
- Packet::Format format = packet.getFormat();
-
- if (!(format & HFO_AH)) {
- throw errors::MalformedAHPacketException();
- }
-
- packet.setSignatureSize(signature_length_);
-
- /* Copy IP+TCP/ICMP header before zeroing them */
- hicn_header_t header_copy;
- hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_,
- &header_copy, false);
-
- std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
-
- packet.resetForHash();
-
- /* Fill the hicn_ah header */
- using namespace std::chrono;
- auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch())
- .count();
- packet.setSignatureTimestamp(now);
- packet.setValidationAlgorithm(suite_);
-
- KeyId key_id;
- key_id.first = (uint8_t *)parcBuffer_Overlay(
- (PARCBuffer *)parcKeyId_GetKeyId(this->key_id_), 0);
- packet.setKeyId(key_id);
-
- /* Calculate hash */
- CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_));
- hasher.init();
- hasher.updateBytes(hicn_packet, header_len + signature_length_);
-
- for (MemBuf *current = payload_chain; current != header_chain;
- current = current->next()) {
- hasher.updateBytes(current->data(), current->length());
- }
-
- CryptoHash hash = hasher.finalize();
- PARCSignature *signature = parcSigner_SignDigestNoAlloc(
- this->signer_, hash.hash_, packet.getSignature(),
- (uint32_t)signature_length_);
- PARCBuffer *buffer = parcSignature_GetSignature(signature);
- size_t bytes_len = parcBuffer_Remaining(buffer);
-
- if (bytes_len > signature_length_) {
- throw errors::MalformedAHPacketException();
- }
-
- hicn_packet_copy_header(format, &header_copy,
- (hicn_header_t *)packet.packet_start_, false);
-
- parcSignature_Release(&signature);
-}
-
-size_t Signer::getSignatureLength() { return signature_length_; }
-
-PARCKeyStore *Signer::getKeyStore() {
- return parcSigner_GetKeyStore(this->signer_);
-}
-
-} // namespace utils
diff --git a/libtransport/src/security/verifier.cc b/libtransport/src/security/verifier.cc
deleted file mode 100644
index 4f6a2be4c..000000000
--- a/libtransport/src/security/verifier.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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/security/key_id.h>
-#include <hicn/transport/security/verifier.h>
-#include <hicn/transport/utils/log.h>
-
-extern "C" {
-#ifndef _WIN32
-TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
-#endif
-#include <hicn/hicn.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);
-}
-
-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() {
- if (signer_) parcSigner_Release(&signer_);
- if (verifier_) parcVerifier_Release(&verifier_);
- parcSecurity_Fini();
-}
-
-/*
- * TODO: Unsupported in libparc
- */
-bool Verifier::hasKey(PARCKeyId *key_id) { return false; }
-
-/*
- * TODO: Signal errors without trap.
- */
-bool Verifier::addKey(PARCKey *key) {
- parcVerifier_AddKey(this->verifier_, key);
- return true;
-}
-
-PARCKeyId *Verifier::addKeyFromPassphrase(const std::string &passphrase,
- CryptoSuite suite) {
- PARCBufferComposer *composer = parcBufferComposer_Create();
- parcBufferComposer_PutString(composer, passphrase.c_str());
- PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
-
- PARCSymmetricKeyStore *symmetricKeyStore =
- parcSymmetricKeyStore_Create(key_buffer);
- signer_ = parcSigner_Create(
- parcSymmetricKeySigner_Create(
- symmetricKeyStore,
- parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite))),
- PARCSymmetricKeySignerAsSigner);
-
- PARCKeyId *key_id = parcSigner_CreateKeyId(signer_);
- PARCKey *key = parcKey_CreateFromSymmetricKey(
- key_id, parcSigner_GetSigningAlgorithm(signer_), key_buffer);
-
- addKey(key);
-
- parcKey_Release(&key);
- parcSymmetricKeyStore_Release(&symmetricKeyStore);
- parcBuffer_Release(&key_buffer);
- parcBufferComposer_Release(&composer);
-
- return key_id;
-}
-
-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);
- PARCBuffer *derEncodedVersion =
- parcCertificate_GetDEREncodedPublicKey(certificate);
- PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate);
-
- PARCKeyId *key_id = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest));
- PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(
- key_id, PARCSigningAlgorithm_RSA, derEncodedVersion);
-
- addKey(key);
-
- parcKey_Release(&key);
- parcCertificate_Release(&certificate);
- parcCertificateFactory_Release(&factory);
-
- return key_id;
-}
-
-int Verifier::verify(const Packet &packet) {
- /* Initialize packet.payload_head_ */
- const_cast<Packet *>(&packet)->separateHeaderPayload();
-
- bool valid = false;
- Packet::Format format = packet.getFormat();
-
- if (!(format & HFO_AH)) {
- throw errors::MalformedAHPacketException();
- }
-
- /* Copy IP+TCP/ICMP header before zeroing them */
- hicn_header_t header_copy;
- hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_,
- &header_copy, false);
-
- /* Get crypto suite */
- PARCCryptoSuite suite =
- static_cast<PARCCryptoSuite>(packet.getValidationAlgorithm());
- PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite);
-
- /* Fetch the key that we will use to verify the signature */
- 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);
-
- /* Fetch signature */
- int ah_payload_len = (int)packet.getSignatureSize();
- uint8_t *_signature = packet.getSignature();
- uint8_t *signature = new uint8_t[ah_payload_len];
- /* TODO Remove signature copy at this point, by not setting to zero */
- /* the validation payload. */
- std::memcpy(signature, _signature, ah_payload_len);
-
- /* Prepare local computation of the signature based on the crypto suite */
- PARCCryptoHasher *hasher_ptr = nullptr;
- switch (CryptoSuite(suite)) {
- case CryptoSuite::DSA_SHA256:
- case CryptoSuite::RSA_SHA256:
- case CryptoSuite::RSA_SHA512:
- case CryptoSuite::ECDSA_256K1: {
- hasher_ptr = parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype);
- break;
- }
- case CryptoSuite::HMAC_SHA256:
- case CryptoSuite::HMAC_SHA512: {
- if (!signer_) return false;
- hasher_ptr = parcSigner_GetCryptoHasher(signer_);
- break;
- }
- default: { return false; }
- }
-
- /* Compute the packet signature locally */
- CryptoHasher crypto_hasher(hasher_ptr);
- CryptoHash hash_computed_locally = getPacketHash(packet, crypto_hasher);
-
- /* Create a signature object from the raw packet signature */
- 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)) {
- delete[] signature;
- 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);
- }
-
- /* Compare the packet signature to the locally computed one */
- valid = parcVerifier_VerifyDigestSignature(
- verifier_, key_id, hash_computed_locally.hash_, suite, signatureToVerify);
-
- /* Restore the fields that were reset */
- hicn_packet_copy_header(format, &header_copy,
- (hicn_header_t *)packet.packet_start_, false);
-
- delete[] signature;
- parcKeyId_Release(&key_id);
- parcBuffer_Release(&bits);
- parcSignature_Release(&signatureToVerify);
-
- return valid;
-}
-
-CryptoHash Verifier::getPacketHash(const Packet &packet,
- CryptoHasher &crypto_hasher) {
- MemBuf *header_chain = packet.header_head_;
- MemBuf *payload_chain = packet.payload_head_;
- Packet::Format format = packet.getFormat();
- int ah_payload_len = (int)packet.getSignatureSize();
- uint8_t *hicn_packet = header_chain->writableData();
- std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
-
- /* Reset fields that should not appear in the signature */
- const_cast<Packet &>(packet).resetForHash();
- crypto_hasher.init().updateBytes(hicn_packet, header_len + ah_payload_len);
-
- for (MemBuf *current = payload_chain; current != header_chain;
- current = current->next()) {
- crypto_hasher.updateBytes(current->data(), current->length());
- }
-
- return crypto_hasher.finalize();
-}
-
-} // namespace utils
diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt
index dd3d1d923..26fe7aee1 100644
--- a/libtransport/src/test/CMakeLists.txt
+++ b/libtransport/src/test/CMakeLists.txt
@@ -13,27 +13,40 @@
include(BuildMacros)
-list(APPEND TESTS
- test_auth
- test_consumer_producer_rtc
- test_core_manifest
- test_event_thread
- test_fec_reedsolomon
- test_interest
- test_packet
+list(APPEND TESTS_SRC
+ main.cc
+ test_auth.cc
+ test_consumer_producer_rtc.cc
+ test_core_manifest.cc
+ test_event_thread.cc
+ test_fec_reedsolomon.cc
+ test_indexer.cc
+ test_interest.cc
+ test_packet.cc
)
-foreach(test ${TESTS})
- build_executable(${test}
- NO_INSTALL
- SOURCES ${test}.cc
- LINK_LIBRARIES ${LIBTRANSPORT_SHARED} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
- INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS} ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
- DEPENDS gtest ${LIBTRANSPORT_SHARED}
- COMPONENT lib${LIBTRANSPORT}
- DEFINITIONS "${COMPILER_DEFINITIONS}"
- LINK_FLAGS ${LINK_FLAGS}
- )
+if (ENABLE_RELY)
+ list(APPEND TESTS_SRC
+ test_fec_rely_wrapper.cc
+ )
+endif()
- add_test_internal(${test})
-endforeach()
+build_executable(unit_tests
+ NO_INSTALL
+ SOURCES ${TESTS_SRC}
+ LINK_LIBRARIES
+ ${LIBRARIES}
+ ${LIBTRANSPORT_STATIC}
+ ${GTEST_LIBRARIES}
+ INCLUDE_DIRS
+ ${LIBTRANSPORT_INCLUDE_DIRS}
+ ${LIBHICN_INCLUDE_DIRS}
+ ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ ${GTEST_INCLUDE_DIRS}
+ DEPENDS gtest ${LIBTRANSPORT_SHARED}
+ COMPONENT ${LIBTRANSPORT_COMPONENT}
+ DEFINITIONS "${COMPILER_DEFINITIONS}"
+ LINK_FLAGS ${LINK_FLAGS}
+)
+
+add_test_internal(unit_tests)
diff --git a/libtransport/src/test/fec_reed_solomon.cc b/libtransport/src/test/fec_reed_solomon.cc
deleted file mode 100644
index 36543c531..000000000
--- a/libtransport/src/test/fec_reed_solomon.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <hicn/transport/interfaces/socket_consumer.h>
-#include <hicn/transport/interfaces/socket_options_keys.h>
-#include <hicn/transport/interfaces/socket_producer.h>
-#include <hicn/transport/interfaces/global_conf_interface.h>
-
-#include <asio/io_service.hpp>
-#include <asio/steady_timer.hpp>
-#include <fec/rs.h>
-
-namespace transport {
-namespace interface {
-
-namespace {
-
-class ConsumerProducerTest : public ::testing::Test,
- public ConsumerSocket::ReadCallback {
- static const constexpr char prefix[] = "b001::1/128";
- static const constexpr char name[] = "b001::1";
- static const constexpr double prod_rate = 1.0e6;
- static const constexpr size_t payload_size = 1200;
- static constexpr std::size_t receive_buffer_size = 1500;
- static const constexpr double prod_interval_microseconds =
- double(payload_size) * 8 * 1e6 / prod_rate;
-
- public:
- ConsumerProducerTest()
- : io_service_(),
- rtc_timer_(io_service_),
- consumer_(TransportProtocolAlgorithms::RTC, io_service_),
- producer_(ProductionProtocolAlgorithms::RTC_PROD, io_service_),
- producer_prefix_(prefix),
- consumer_name_(name),
- packets_sent_(0),
- packets_received_(0) {
- global_config::IoModuleConfiguration config;
- config.name = "loopback_module";
- config.set();
- }
-
- virtual ~ConsumerProducerTest() {
- // 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() override {
- // Code here will be called immediately after the constructor (right
- // before each test).
-
- auto ret = consumer_.setSocketOption(
- ConsumerCallbacksOptions::READ_CALLBACK, this);
- ASSERT_EQ(ret, SOCKET_OPTION_SET);
-
- consumer_.connect();
- producer_.registerPrefix(producer_prefix_);
- producer_.connect();
- }
-
- virtual void TearDown() override {
- // Code here will be called immediately after each test (right
- // before the destructor).
- }
-
- void setTimer() {
- using namespace std::chrono;
- rtc_timer_.expires_from_now(
- microseconds(unsigned(prod_interval_microseconds)));
- rtc_timer_.async_wait(std::bind(&ConsumerProducerTest::produceRTCPacket,
- this, std::placeholders::_1));
- }
-
- void produceRTCPacket(const std::error_code &ec) {
- if (ec) {
- FAIL() << "Failed to schedule packet production";
- io_service_.stop();
- }
-
- producer_.produceDatagram(consumer_name_, payload_, payload_size);
- packets_sent_++;
- setTimer();
- }
-
- // Consumer callback
- bool isBufferMovable() noexcept override { return false; }
-
- void getReadBuffer(uint8_t **application_buffer,
- size_t *max_length) override {
- *application_buffer = receive_buffer_;
- *max_length = receive_buffer_size;
- }
-
- void readDataAvailable(std::size_t length) noexcept override {}
-
- size_t maxBufferSize() const override { return receive_buffer_size; }
-
- void readError(const std::error_code ec) noexcept override {
- FAIL() << "Error while reading from RTC socket";
- io_service_.stop();
- }
-
- void readSuccess(std::size_t total_size) noexcept override {
- packets_received_++;
- }
-
- asio::io_service io_service_;
- asio::steady_timer rtc_timer_;
- ConsumerSocket consumer_;
- ProducerSocket producer_;
- core::Prefix producer_prefix_;
- core::Name consumer_name_;
- uint8_t payload_[payload_size];
- uint8_t receive_buffer_[payload_size];
-
- uint64_t packets_sent_;
- uint64_t packets_received_;
-};
-
-const char ConsumerProducerTest::prefix[];
-const char ConsumerProducerTest::name[];
-
-} // namespace
-
-TEST_F(ConsumerProducerTest, EndToEnd) {
- produceRTCPacket(std::error_code());
- consumer_.consume(consumer_name_);
-
- io_service_.run();
-}
-
-} // namespace interface
-
-} // 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/test/fec_rely.cc b/libtransport/src/test/fec_rely.cc
deleted file mode 100644
index e7745bae5..000000000
--- a/libtransport/src/test/fec_rely.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <hicn/transport/interfaces/socket_consumer.h>
-#include <hicn/transport/interfaces/socket_options_keys.h>
-#include <hicn/transport/interfaces/socket_producer.h>
-#include <hicn/transport/interfaces/global_conf_interface.h>
-
-#include <asio/io_service.hpp>
-#include <asio/steady_timer.hpp>
-
-#include <rely/encoder.hpp>
-#include <rely/decoder.hpp>
-
-namespace transport {
-namespace interface {
-
-namespace {
-
-class ConsumerProducerTest : public ::testing::Test,
- public ConsumerSocket::ReadCallback {
- static const constexpr char prefix[] = "b001::1/128";
- static const constexpr char name[] = "b001::1";
- static const constexpr double prod_rate = 1.0e6;
- static const constexpr size_t payload_size = 1200;
- static constexpr std::size_t receive_buffer_size = 1500;
- static const constexpr double prod_interval_microseconds =
- double(payload_size) * 8 * 1e6 / prod_rate;
-
- public:
- ConsumerProducerTest()
- : io_service_(),
- rtc_timer_(io_service_),
- consumer_(TransportProtocolAlgorithms::RTC, io_service_),
- producer_(ProductionProtocolAlgorithms::RTC_PROD, io_service_),
- producer_prefix_(prefix),
- consumer_name_(name),
- packets_sent_(0),
- packets_received_(0) {
- global_config::IoModuleConfiguration config;
- config.name = "loopback_module";
- config.set();
- }
-
- virtual ~ConsumerProducerTest() {
- // 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() override {
- // Code here will be called immediately after the constructor (right
- // before each test).
-
- auto ret = consumer_.setSocketOption(
- ConsumerCallbacksOptions::READ_CALLBACK, this);
- ASSERT_EQ(ret, SOCKET_OPTION_SET);
-
- consumer_.connect();
- producer_.registerPrefix(producer_prefix_);
- producer_.connect();
- }
-
- virtual void TearDown() override {
- // Code here will be called immediately after each test (right
- // before the destructor).
- }
-
- void setTimer() {
- using namespace std::chrono;
- rtc_timer_.expires_from_now(
- microseconds(unsigned(prod_interval_microseconds)));
- rtc_timer_.async_wait(std::bind(&ConsumerProducerTest::produceRTCPacket,
- this, std::placeholders::_1));
- }
-
- void produceRTCPacket(const std::error_code &ec) {
- if (ec) {
- FAIL() << "Failed to schedule packet production";
- io_service_.stop();
- }
-
- producer_.produceDatagram(consumer_name_, payload_, payload_size);
- packets_sent_++;
- setTimer();
- }
-
- // Consumer callback
- bool isBufferMovable() noexcept override { return false; }
-
- void getReadBuffer(uint8_t **application_buffer,
- size_t *max_length) override {
- *application_buffer = receive_buffer_;
- *max_length = receive_buffer_size;
- }
-
- void readDataAvailable(std::size_t length) noexcept override {}
-
- size_t maxBufferSize() const override { return receive_buffer_size; }
-
- void readError(const std::error_code ec) noexcept override {
- FAIL() << "Error while reading from RTC socket";
- io_service_.stop();
- }
-
- void readSuccess(std::size_t total_size) noexcept override {
- packets_received_++;
- }
-
- asio::io_service io_service_;
- asio::steady_timer rtc_timer_;
- ConsumerSocket consumer_;
- ProducerSocket producer_;
- core::Prefix producer_prefix_;
- core::Name consumer_name_;
- uint8_t payload_[payload_size];
- uint8_t receive_buffer_[payload_size];
-
- uint64_t packets_sent_;
- uint64_t packets_received_;
-};
-
-const char ConsumerProducerTest::prefix[];
-const char ConsumerProducerTest::name[];
-
-} // namespace
-
-TEST_F(ConsumerProducerTest, EndToEnd) {
- produceRTCPacket(std::error_code());
- consumer_.consume(consumer_name_);
-
- io_service_.run();
-}
-
-} // namespace interface
-
-} // 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/test/main.cc b/libtransport/src/test/main.cc
new file mode 100644
index 000000000..a4d7ce1b3
--- /dev/null
+++ b/libtransport/src/test/main.cc
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+int main(int argc, char **argv) {
+ srand(time(0));
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+} \ No newline at end of file
diff --git a/libtransport/src/test/test_auth.cc b/libtransport/src/test/test_auth.cc
index 976981cce..db1c3b52f 100644
--- a/libtransport/src/test/test_auth.cc
+++ b/libtransport/src/test/test_auth.cc
@@ -14,7 +14,7 @@
*/
#include <gtest/gtest.h>
-#include <hicn/transport/auth/crypto_hash_type.h>
+#include <hicn/transport/auth/crypto_hash.h>
#include <hicn/transport/auth/identity.h>
#include <hicn/transport/auth/signer.h>
#include <hicn/transport/auth/verifier.h>
@@ -45,14 +45,15 @@ TEST_F(AuthTest, VoidVerifier) {
// Verify that VoidVerifier validates the packet
std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>();
- ASSERT_EQ(verifier->verifyPacket(&packet), true);
- ASSERT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+ EXPECT_EQ(verifier->verifyPacket(&packet), true);
+ EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
}
-TEST_F(AuthTest, RSAVerifier) {
+TEST_F(AuthTest, AsymmetricRSA) {
// Create the RSA signer from an Identity object
Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
30, "RSAVerifier");
+
std::shared_ptr<Signer> signer = identity.getSigner();
// Create a content object
@@ -66,21 +67,125 @@ TEST_F(AuthTest, RSAVerifier) {
signer->signPacket(&packet);
// Create the RSA verifier
- PARCKey *key = parcSigner_CreatePublicKey(signer->getParcSigner());
std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(key);
+ std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+
+ EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
+ EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
+ EXPECT_EQ(signer->getSuite(), CryptoSuite::RSA_SHA256);
+ EXPECT_EQ(signer->getSignatureSize(), 128u);
+ EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+}
+
+TEST_F(AuthTest, AsymmetricBufferRSA) {
+ // Create the RSA signer from an Identity object
+ Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
+ 30, "RSAVerifier");
+
+ std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
+ std::string payload = "bonjour";
- ASSERT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
- ASSERT_EQ(signer->getCryptoHashType(), CryptoHashType::SHA_256);
- ASSERT_EQ(signer->getCryptoSuite(), CryptoSuite::RSA_SHA256);
- ASSERT_EQ(signer->getSignatureSize(), 128u);
- ASSERT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+ std::vector<uint8_t> buffer(payload.begin(), payload.end());
+ signer->signBuffer(buffer);
+ std::vector<uint8_t> sig = signer->getSignature();
- // Release PARC objects
- parcKey_Release(&key);
+ std::shared_ptr<X509> cert = identity.getCertificate();
+ AsymmetricVerifier verif(cert);
+ bool res = verif.verifyBuffer(
+ buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
+ CryptoHashType::SHA256);
+ EXPECT_EQ(res, true);
}
-TEST_F(AuthTest, HMACVerifier) {
+TEST_F(AuthTest, AsymmetricBufferDSA) {
+ // Create the DSA signer from an Identity object
+ Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
+ 30, "DSAVerifier");
+
+ std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
+ std::string payload = "bonjour";
+
+ std::vector<uint8_t> buffer(payload.begin(), payload.end());
+ signer->signBuffer(buffer);
+ std::vector<uint8_t> sig = signer->getSignature();
+
+ std::shared_ptr<X509> cert = identity.getCertificate();
+ AsymmetricVerifier verif(cert);
+ bool res = verif.verifyBuffer(
+ buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
+ CryptoHashType::SHA256);
+ EXPECT_EQ(res, true);
+}
+
+TEST_F(AuthTest, AsymmetricVerifierDSA) {
+ // Create the DSA signer from an Identity object
+ Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
+ 30, "DSAVerifier");
+
+ std::shared_ptr<Signer> signer = identity.getSigner();
+
+ // Create a content object
+ core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
+
+ // Fill it with bogus data
+ uint8_t buffer[256] = {0};
+ packet.appendPayload(buffer, 256);
+ // this test has to be done before the signature is compute
+ // EXPECT_EQ(signer->getSignatureSize(), 256u);
+ signer->signPacket(&packet);
+ std::shared_ptr<Verifier> verifier =
+ std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+
+ EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
+ EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
+ EXPECT_EQ(signer->getSuite(), CryptoSuite::DSA_SHA256);
+ EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+}
+
+TEST_F(AuthTest, AsymmetricBufferECDSA) {
+ // Create the ECDSA signer from an Identity object
+ Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
+ 256u, 30, "ECDSAVerifier");
+
+ std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
+ std::string payload = "bonjour";
+
+ std::vector<uint8_t> buffer(payload.begin(), payload.end());
+ signer->signBuffer(buffer);
+ std::vector<uint8_t> sig = signer->getSignature();
+
+ std::shared_ptr<X509> cert = identity.getCertificate();
+ AsymmetricVerifier verif(cert);
+ bool res = verif.verifyBuffer(
+ buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
+ CryptoHashType::SHA256);
+ EXPECT_EQ(res, true);
+}
+
+TEST_F(AuthTest, AsymmetricVerifierECDSA) {
+ Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
+ 256u, 30, "ECDSAVerifier");
+
+ std::shared_ptr<Signer> signer = identity.getSigner();
+ std::shared_ptr<Verifier> verifier =
+ std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+ // Create a content object
+ for (int i = 0; i < 100; i++) {
+ core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
+
+ // Fill it with bogus data
+ uint8_t buffer[256] = {0};
+ packet.appendPayload(buffer, 256);
+ signer->signPacket(&packet);
+
+ EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
+ EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
+ EXPECT_EQ(signer->getSuite(), CryptoSuite::ECDSA_SHA256);
+ EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+ }
+}
+
+TEST_F(AuthTest, HMACbuffer) {
// Create the HMAC signer from a passphrase
std::shared_ptr<Signer> signer =
std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256, PASSPHRASE);
@@ -88,6 +193,25 @@ TEST_F(AuthTest, HMACVerifier) {
// Create a content object
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
+ std::string payload = "bonjour";
+ std::vector<uint8_t> buffer(payload.begin(), payload.end());
+ signer->signBuffer(buffer);
+ std::vector<uint8_t> sig = signer->getSignature();
+ SymmetricVerifier hmac(PASSPHRASE);
+ bool res = hmac.verifyBuffer(
+ buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
+ CryptoHashType::SHA256);
+ EXPECT_EQ(res, true);
+}
+
+TEST_F(AuthTest, HMACVerifier) {
+ // Create the HMAC signer from a passphrase
+ std::shared_ptr<SymmetricSigner> signer =
+ std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256, PASSPHRASE);
+
+ // Create a content object
+ core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
+
// Fill it with bogus data
uint8_t buffer[256] = {0};
packet.appendPayload(buffer, 256);
@@ -99,11 +223,11 @@ TEST_F(AuthTest, HMACVerifier) {
std::shared_ptr<Verifier> verifier =
std::make_shared<SymmetricVerifier>(PASSPHRASE);
- ASSERT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
- ASSERT_EQ(signer->getCryptoHashType(), CryptoHashType::SHA_256);
- ASSERT_EQ(signer->getCryptoSuite(), CryptoSuite::HMAC_SHA256);
- ASSERT_EQ(signer->getSignatureSize(), 32u);
- ASSERT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
+ EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
+ EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
+ EXPECT_EQ(signer->getSuite(), CryptoSuite::HMAC_SHA256);
+ EXPECT_EQ(signer->getSignatureSize(), 32u);
+ EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
}
} // namespace auth
diff --git a/libtransport/src/test/test_consumer_producer_rtc.cc b/libtransport/src/test/test_consumer_producer_rtc.cc
index 87385971a..8541a9e1a 100644
--- a/libtransport/src/test/test_consumer_producer_rtc.cc
+++ b/libtransport/src/test/test_consumer_producer_rtc.cc
@@ -14,14 +14,12 @@
*/
#include <gtest/gtest.h>
+#include <hicn/transport/core/asio_wrapper.h>
#include <hicn/transport/interfaces/global_conf_interface.h>
#include <hicn/transport/interfaces/socket_consumer.h>
#include <hicn/transport/interfaces/socket_options_keys.h>
#include <hicn/transport/interfaces/socket_producer.h>
-#include <asio/io_service.hpp>
-#include <asio/steady_timer.hpp>
-
namespace transport {
namespace interface {
@@ -151,7 +149,7 @@ const char ConsumerProducerTest::name[];
} // namespace
-TEST_F(ConsumerProducerTest, EndToEnd) {
+TEST_F(ConsumerProducerTest, DISABLED_EndToEnd) {
produceRTCPacket(std::error_code());
consumer_.consume(consumer_name_);
setStopTimer();
@@ -165,12 +163,3 @@ TEST_F(ConsumerProducerTest, EndToEnd) {
} // namespace interface
} // namespace transport
-
-int main(int argc, char **argv) {
-#if 0
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-#else
- return 0;
-#endif
-} \ No newline at end of file
diff --git a/libtransport/src/test/test_core_manifest.cc b/libtransport/src/test/test_core_manifest.cc
index f98147d43..93f4e87cb 100644
--- a/libtransport/src/test/test_core_manifest.cc
+++ b/libtransport/src/test/test_core_manifest.cc
@@ -16,7 +16,7 @@
#include <core/manifest_format_fixed.h>
#include <core/manifest_inline.h>
#include <gtest/gtest.h>
-#include <hicn/transport/auth/crypto_hash_type.h>
+#include <hicn/transport/auth/crypto_hash.h>
#include <test/packet_samples.h>
#include <climits>
@@ -124,9 +124,9 @@ TEST_F(ManifestTest, SetManifestType) {
TEST_F(ManifestTest, SetHashAlgorithm) {
manifest1_.clear();
- auth::CryptoHashType hash1 = auth::CryptoHashType::SHA_512;
- auth::CryptoHashType hash2 = auth::CryptoHashType::CRC32C;
- auth::CryptoHashType hash3 = auth::CryptoHashType::SHA_256;
+ auth::CryptoHashType hash1 = auth::CryptoHashType::SHA512;
+ auth::CryptoHashType hash2 = auth::CryptoHashType::BLAKE2B512;
+ auth::CryptoHashType hash3 = auth::CryptoHashType::SHA256;
manifest1_.setHashAlgorithm(hash1);
auto type_returned1 = manifest1_.getHashAlgorithm();
@@ -191,9 +191,9 @@ TEST_F(ManifestTest, SetSuffixList) {
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], auth::CryptoHash(data[i].data(), data[i].size(),
- auth::CryptoHashType::SHA_256));
+ entries[i] = std::make_pair(suffixes[i],
+ auth::CryptoHash(data[i].data(), data[i].size(),
+ auth::CryptoHashType::SHA256));
manifest1_.addSuffixHash(entries[i].first, entries[i].second);
}
@@ -223,8 +223,3 @@ TEST_F(ManifestTest, SetSuffixList) {
} // namespace core
} // namespace transport
-
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/libtransport/src/test/test_event_thread.cc b/libtransport/src/test/test_event_thread.cc
index e66b49f10..549ff9c1a 100644
--- a/libtransport/src/test/test_event_thread.cc
+++ b/libtransport/src/test/test_event_thread.cc
@@ -71,7 +71,7 @@ double stdDeviation(const unsigned long samples[], int size) {
} // namespace
-TEST_F(EventThreadTest, SchedulingDelay) {
+TEST_F(EventThreadTest, DISABLED_SchedulingDelay) {
using namespace std::chrono;
const size_t size = 1000000;
std::vector<unsigned long> samples(size);
@@ -95,12 +95,3 @@ TEST_F(EventThreadTest, SchedulingDelay) {
}
} // namespace utils
-
-int main(int argc, char **argv) {
-#if 0
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-#else
- return 0;
-#endif
-} \ No newline at end of file
diff --git a/libtransport/src/test/test_fec_reedsolomon.cc b/libtransport/src/test/test_fec_reedsolomon.cc
index 3b10b7307..c7e10d111 100644
--- a/libtransport/src/test/test_fec_reedsolomon.cc
+++ b/libtransport/src/test/test_fec_reedsolomon.cc
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <core/rs.h>
#include <gtest/gtest.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec/rs.h>
#include <algorithm>
#include <iostream>
#include <random>
namespace transport {
-namespace core {
+namespace protocol {
-double ReedSolomonTest(int k, int n, int size) {
- fec::encoder encoder(k, n);
- fec::decoder decoder(k, n);
+double ReedSolomonTest(int k, int n, int seq_offset, int size) {
+ fec::RSEncoder encoder(k, n, seq_offset);
+ fec::RSDecoder decoder(k, n, seq_offset);
std::vector<fec::buffer> tx_block(k);
std::vector<fec::buffer> rx_block(k);
@@ -36,27 +36,31 @@ double ReedSolomonTest(int k, int n, int size) {
int run = 0;
int iterations = 100;
- auto &packet_manager = PacketManager<>::getInstance();
-
- encoder.setFECCallback([&tx_block](std::vector<fec::buffer> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p));
- }
- });
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ encoder.setFECCallback(
+ [&tx_block](
+ std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ tx_block.emplace_back(std::move(p).second);
+ }
+ });
- decoder.setFECCallback([&](std::vector<fec::buffer> &source_packets) {
- for (int i = 0; i < k; i++) {
- // Compare decoded source packets with original transmitted packets.
- if (*tx_block[i] != *source_packets[i]) {
- count++;
- }
- }
- });
+ decoder.setFECCallback(
+ [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
+ for (int i = 0; i < k; i++) {
+ // Compare decoded source packets with original transmitted packets.
+ if (*tx_block[i] != *source_packets[i].second) {
+ count++;
+ }
+ }
+ });
do {
// Discard eventual packet appended in previous callback call
tx_block.erase(tx_block.begin() + k, tx_block.end());
+ auto _seq_offet = seq_offset;
// Initialization. Feed encoder with first k source packets
for (int i = 0; i < k; i++) {
@@ -74,8 +78,8 @@ double ReedSolomonTest(int k, int n, int size) {
std::generate(packet->writableData(), packet->writableTail(), rand);
std::fill(packet->writableData(), packet->writableTail(), i + 1);
- // Set first byte of payload to i, to reorder at receiver side
- packet->writableData()[0] = uint8_t(i);
+ // Set first byte of payload to seq_offset, to reorder at receiver side
+ packet->writableData()[0] = uint8_t(_seq_offet++);
// Store packet in tx buffer and clear rx buffer
tx_block[i] = std::move(packet);
@@ -99,10 +103,11 @@ double ReedSolomonTest(int k, int n, int size) {
rx_block[rxi++] = tx_block[i];
if (i < k) {
// Source packet
- decoder.consume(rx_block[rxi - 1], rx_block[rxi - 1]->data()[0]);
+ decoder.consumeSource(rx_block[rxi - 1],
+ rx_block[rxi - 1]->data()[0]);
} else {
// Repair packet
- decoder.consume(rx_block[rxi - 1]);
+ decoder.consumeRepair(rx_block[rxi - 1]);
}
}
@@ -118,10 +123,10 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
int n = 24;
int size = 1000;
- fec::encoder encoder(k, n);
- fec::decoder decoder(k, n);
+ fec::RSEncoder encoder(k, n);
+ fec::RSDecoder decoder(k, n);
- auto &packet_manager = PacketManager<>::getInstance();
+ auto &packet_manager = core::PacketManager<>::getInstance();
std::vector<std::pair<fec::buffer, uint32_t>> tx_block;
std::vector<std::pair<fec::buffer, uint32_t>> rx_block;
@@ -133,28 +138,31 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
int tx_packets = k * n_sourceblocks;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
- encoder.setFECCallback([&](std::vector<fec::buffer> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p), ++i);
- }
+ encoder.setFECCallback(
+ [&](std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ tx_block.emplace_back(std::move(p.second), ++i);
+ }
- EXPECT_EQ(tx_block.size(), size_t(n));
+ EXPECT_EQ(tx_block.size(), size_t(n));
- // Select k packets to send, including at least one symbol. We start from
- // the end for this reason.
- for (int j = n - 1; j > n - k - 1; j--) {
- rx_block.emplace_back(std::move(tx_block[j]));
- }
+ // Select k packets to send, including at least one symbol. We start
+ // from the end for this reason.
+ for (int j = n - 1; j > n - k - 1; j--) {
+ rx_block.emplace_back(std::move(tx_block[j]));
+ }
- // Clear tx block for next source block
- tx_block.clear();
- encoder.clear();
- });
+ // Clear tx block for next source block
+ tx_block.clear();
+ encoder.clear();
+ });
// The decode callback must be called exactly n_sourceblocks times
decoder.setFECCallback(
- [&](std::vector<fec::buffer> &source_packets) { count++; });
+ [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
+ count++;
+ });
// Produce n * n_sourceblocks
// - ( k ) * n_sourceblocks source packets
@@ -194,10 +202,10 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
int index = p.second % n;
if (index < k) {
// Source packet
- decoder.consume(p.first, p.second);
+ decoder.consumeSource(p.first, p.second);
} else {
// Repair packet
- decoder.consume(p.first);
+ decoder.consumeRepair(p.first);
}
}
@@ -205,66 +213,22 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
EXPECT_EQ(count, n_sourceblocks);
}
-TEST(ReedSolomonTest, RSk1n3) {
- int k = 1;
- int n = 3;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk6n10) {
- int k = 6;
- int n = 10;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk8n32) {
- int k = 8;
- int n = 32;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk16n24) {
- int k = 16;
- int n = 24;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk10n30) {
- int k = 10;
- int n = 30;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk10n40) {
- int k = 10;
- int n = 40;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk10n60) {
- int k = 10;
- int n = 60;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonTest, RSk10n90) {
- int k = 10;
- int n = 90;
- int size = 1000;
- EXPECT_LE(ReedSolomonTest(k, n, size), 0);
-}
-
-TEST(ReedSolomonMultiBlockTest, RSMB1) {
- int blocks = 1;
- ReedSolomonMultiBlockTest(blocks);
-}
+/**
+ * @brief Use foreach_rs_fec_type to automatically generate the code of the
+ * tests and avoid copy/paste the same function.
+ */
+#define _(name, k, n) \
+ TEST(ReedSolomonTest, RSK##k##N##n) { \
+ int K = k; \
+ int N = n; \
+ int seq_offset = 0; \
+ int size = 1000; \
+ EXPECT_LE(ReedSolomonTest(K, N, seq_offset, size), 0); \
+ seq_offset = 12345; \
+ EXPECT_LE(ReedSolomonTest(K, N, seq_offset, size), 0); \
+ }
+foreach_rs_fec_type
+#undef _
TEST(ReedSolomonMultiBlockTest, RSMB10) {
int blocks = 10;
@@ -281,11 +245,5 @@ TEST(ReedSolomonMultiBlockTest, RSMB1000) {
ReedSolomonMultiBlockTest(blocks);
}
-int main(int argc, char **argv) {
- srand(time(0));
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
-
-} // namespace core
+} // namespace protocol
} // namespace transport
diff --git a/libtransport/src/test/test_fec_rely_wrapper.cc b/libtransport/src/test/test_fec_rely_wrapper.cc
new file mode 100644
index 000000000..c5b73f8d2
--- /dev/null
+++ b/libtransport/src/test/test_fec_rely_wrapper.cc
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/utils/log.h>
+#include <protocols/fec/rely.h>
+
+#include <queue>
+
+namespace transport {
+namespace protocol {
+
+std::string printMissing(
+ const std::map<uint32_t, core::ContentObject::Ptr> &missing) {
+ std::stringstream stream;
+
+ for (auto &[seq, packet] : missing) {
+ stream << " " << seq;
+ }
+
+ stream << "\n";
+
+ return stream.str();
+}
+
+/**
+ * @brief Test encode-decode operations performed using the wrapper for rely
+ *
+ * @param k Number of source symbols
+ * @param n Sum of source symbols and repair symbols
+ * @param max_packet_size The max packet size the decoder will expect.
+ * @param timeout The timeout used by rely
+ * https://rely.steinwurf.com/docs/6.1.0/design/timeout_configuration.html
+ * @param max_iterations The number of packets to send
+ * @param loss_rate The loss rate
+ */
+void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
+ int64_t timeout, uint32_t max_iterations,
+ int loss_rate) {
+ // Create 1 encoder and 1 decoder
+ fec::RelyEncoder _encoder(k, n);
+ fec::RelyDecoder _decoder(k, n);
+
+ // Seed the pseudo-random with known value to always get same loss pattern
+ srand(k * n);
+
+ // We will interact with rely encoder/decoder using the interface
+ fec::ProducerFEC &encoder = _encoder;
+ fec::ConsumerFEC &decoder = _decoder;
+
+ // Initialize current iteration
+ uint32_t iterations = 0;
+
+ // Packet allocator
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // Store packets to verify them in the decoder callback
+ std::map<uint32_t, core::ContentObject::Ptr> saved_packets;
+
+ // Save repair packets here in encoder callback
+ std::queue<fec::buffer> pending_repair_packets;
+
+ // Set callback called by encoder when a buffer is required.
+ encoder.setBufferCallback([](std::size_t size) -> fec::buffer {
+ auto ret =
+ core::PacketManager<>::getInstance().getPacket<core::ContentObject>();
+ ret->updateLength(size);
+ ret->append(size);
+ ret->trimStart(ret->headerSize());
+ assert(ret->length() >= size);
+
+ return ret;
+ });
+
+ // Set callback to be called by encoder when repair packets are ready
+ encoder.setFECCallback(
+ [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+ // We must get n - k symbols
+ EXPECT_EQ(packets.size(), n - k);
+ // TRANSPORT_LOGD("Got %zu symbols", packets.size());
+
+ // Save symbols in pending_repair_packets queue and increment iterations
+ for (auto &packet : packets) {
+ ++iterations;
+ pending_repair_packets.push(packet.second);
+ }
+ });
+
+ // Set callback to be called when decoder recover a packet
+ decoder.setFECCallback(
+ [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
+ for (auto &packet : packets) {
+ // TRANSPORT_LOGD("Recovering packet %u", packet.first);
+
+ // Ensure recovered packet is in packets actually produced by encoder
+ auto original = saved_packets.find(packet.first);
+ ASSERT_TRUE(original != saved_packets.end());
+ auto &original_packet = *original->second;
+
+ // Remove additional headers at the beginning of the packet. This may
+ // change in the future.
+ original_packet.trimStart(60 /* Ip + TCP */ + 28 /* Rely header */ +
+ 4 /* Packet size */);
+
+ // Recovered packet should be equal to the original one
+ EXPECT_TRUE(original_packet == *packet.second);
+
+ // Restore removed headers
+ original_packet.prepend(60 + 28 + 4);
+
+ // Erase packet from saved packet list
+ saved_packets.erase(original);
+ }
+ });
+
+ // Send max_iterations packets from encoder to decoder
+ while (iterations < max_iterations) {
+ // Create a payload, the size is between 50 and 1350 bytes.
+ auto payload_size = 50 + (rand() % 1300);
+ uint8_t payload[max_packet_size];
+ std::generate(payload, payload + payload_size, rand);
+
+ // Get a packet from global pool and set name
+ auto buffer = packet_manager.getPacket<core::ContentObject>();
+ buffer->setName(core::Name("b001::abcd", iterations));
+
+ // Get offset
+ auto offset = buffer->headerSize();
+
+ // Copy payload into packet. We keep the payload to compare returned packet
+ // with original one (since rely encoder does modify the packet by adding
+ // its own header).
+ buffer->appendPayload(payload, payload_size);
+
+ // Save packet in the saving_packets list
+ // TRANSPORT_LOGD("Saving packet with index %lu", iterations);
+ saved_packets.emplace(iterations, buffer);
+
+ // Feed buffer into the encoder. This will eventually trigger a call to the
+ // FEC callback as soon as k packets are fed into the endocer.
+ encoder.onPacketProduced(*buffer, offset);
+
+ // Check returned packet. We calculate the difference in size and we compare
+ // only the part of the returned packet corresponding to the original
+ // payload. Rely should only add a header and should not modify the actual
+ // payload content. If it does it, this check will fail.
+ auto diff = buffer->length() - payload_size - offset;
+ // TRANSPORT_LOGD("Difference is %zu", diff);
+ auto cmp =
+ std::memcmp(buffer->data() + offset + diff, payload, payload_size);
+ EXPECT_FALSE(cmp);
+
+ // Drop condition. Id addition to the loss rate, we ensure that no drops are
+ // perfomed in the last 10% of the total iterations. This is done because
+ // rely uses a sliding-window mechanism to recover, and if we suddenly stop
+ // we may not be able to recover missing packets that would be recovered
+ // using future packets that are not created in the test. For this reason,
+ // we ensure the test ends without losses.
+#define DROP_CONDITION(loss_rate, max_iterations) \
+ (rand() % 100) >= loss_rate || iterations >= max_iterations * 0.9
+
+ // Handle the source packet to the decoder, id drop condition returns true
+ if (DROP_CONDITION(loss_rate, max_iterations)) {
+ // Pass packet to decoder
+ // TRANSPORT_LOGD("Passing packet %u to decoder",
+ // buffer->getName().getSuffix());
+ decoder.onDataPacket(*buffer, offset);
+ } else {
+ // TRANSPORT_LOGD("Packet %u, dropped", buffer->getName().getSuffix());
+ }
+
+ // Check if previous call to encoder.consumer() generated repair packets,
+ // and if yes, feed them to the decoder.
+ while (pending_repair_packets.size()) {
+ // Also repair packets can be lost
+ if (DROP_CONDITION(loss_rate, max_iterations)) {
+ auto &packet = pending_repair_packets.front();
+ // TRANSPORT_LOGD("Passing packet %u to decoder", iterations);
+ core::ContentObject &co = (core::ContentObject &)(*packet);
+ decoder.onDataPacket(co, 0);
+ } else {
+ // TRANSPORT_LOGD("Packet (repair) %u dropped", iterations);
+ }
+
+ // Remove packet from the queue
+ pending_repair_packets.pop();
+ }
+
+ ++iterations;
+ }
+
+ // We expect this test to terminate with a full recover of all the packets and
+ // 0.001 residual losses
+ EXPECT_LE(saved_packets.size(), iterations * 0.001)
+ << printMissing(saved_packets);
+
+ // Reset seed
+ srand(time(0));
+}
+
+/**
+ * @brief Use foreach_rely_fec_type to automatically generate the code of the
+ * tests and avoid copy/paste the same function.
+ */
+#define _(name, k, n) \
+ TEST(RelyTest, RelyK##k##N##n) { \
+ int K = k; \
+ int N = n; \
+ uint32_t max_iterations = 1000; \
+ int size = 1400; \
+ int64_t timeout = 120; \
+ int loss_rate = 10; \
+ testRelyEncoderDecoder(K, N, size, timeout, max_iterations, loss_rate); \
+ }
+foreach_rely_fec_type
+#undef _
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_indexer.cc b/libtransport/src/test/test_indexer.cc
new file mode 100644
index 000000000..9c12e2037
--- /dev/null
+++ b/libtransport/src/test/test_indexer.cc
@@ -0,0 +1,322 @@
+
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <protocols/incremental_indexer_bytestream.h>
+#include <protocols/indexer.h>
+#include <protocols/rtc/rtc_indexer.h>
+
+#include <algorithm>
+#include <iostream>
+#include <random>
+
+namespace transport {
+namespace protocol {
+
+class IncrementalIndexerTest : public ::testing::Test {
+ protected:
+ IncrementalIndexerTest() : indexer_(nullptr, nullptr) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~IncrementalIndexerTest() {
+ // 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).
+ }
+
+ IncrementalIndexer indexer_;
+};
+
+class RtcIndexerTest : public ::testing::Test {
+ protected:
+ RtcIndexerTest() : indexer_(nullptr, nullptr) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~RtcIndexerTest() {
+ // 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).
+ indexer_.setFirstSuffix(0);
+ indexer_.reset();
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ }
+
+ static const constexpr uint32_t LIMIT = (1 << 31);
+ rtc::RtcIndexer<LIMIT> indexer_;
+};
+
+void testIncrement(Indexer &indexer) {
+ // As a first index we should get zero
+ auto index = indexer.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(0));
+
+ // Check if the sequence works for consecutive incremental numbers
+ for (uint32_t i = 1; i < 4096; i++) {
+ index = indexer.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+
+ index = indexer.getNextSuffix();
+ EXPECT_NE(index, uint32_t(0));
+}
+
+void testJump(Indexer &indexer) {
+ // Fist suffix is 0
+ auto index = indexer.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(0));
+
+ // Next suffix should be 1, but we jump to 12345
+ uint32_t jump = 12345;
+ indexer.jumpToIndex(jump);
+
+ // This takes place immediately
+ index = indexer.getNextSuffix();
+ EXPECT_EQ(index, jump);
+}
+
+TEST_F(IncrementalIndexerTest, TestReset) {
+ testIncrement(indexer_);
+
+ // Reset the indexer
+ indexer_.reset();
+
+ // Now it should startfrom zero again
+ for (uint32_t i = 0; i < 4096; i++) {
+ auto index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+}
+
+TEST_F(IncrementalIndexerTest, TestGetSuffix) { testIncrement(indexer_); }
+
+TEST_F(IncrementalIndexerTest, TestGetNextReassemblySegment) {
+ // Test suffixes for reassembly are not influenced by download suffixed
+ // increment
+ for (uint32_t i = 0; i < 4096; i++) {
+ auto index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+
+ for (uint32_t i = 0; i < 4096; i++) {
+ auto index = indexer_.getNextReassemblySegment();
+ EXPECT_EQ(index, i);
+ }
+}
+
+TEST_F(IncrementalIndexerTest, TestJumpToIndex) { testJump(indexer_); }
+
+TEST_F(IncrementalIndexerTest, TestGetFinalSuffix) {
+ // Since final suffix hasn't been discovered, it should be invalid_index
+ auto final_suffix = indexer_.getFinalSuffix();
+ ASSERT_EQ(final_suffix, Indexer::invalid_index);
+}
+
+TEST_F(IncrementalIndexerTest, TestMaxLimit) {
+ // Jump to max value for uint32_t
+ indexer_.jumpToIndex(std::numeric_limits<uint32_t>::max());
+ auto ret = indexer_.getNextSuffix();
+ ASSERT_EQ(ret, Indexer::invalid_index);
+
+ // Now the indexer should always return invalid_index
+ for (uint32_t i = 0; i < 4096; i++) {
+ ret = indexer_.getNextSuffix();
+ EXPECT_EQ(ret, Indexer::invalid_index);
+ }
+}
+
+TEST_F(IncrementalIndexerTest, TestSetFirstSuffix) {
+ // Set first suffix before starting
+ uint32_t start = 1234567890;
+ indexer_.setFirstSuffix(1234567890);
+
+ // The first suffix set should take place only after a reset
+ auto index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(0));
+
+ indexer_.reset();
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, start);
+}
+
+TEST_F(IncrementalIndexerTest, TestIsFinalSuffixDiscovered) {
+ // Final suffix should not be discovererd
+ auto ret = indexer_.isFinalSuffixDiscovered();
+ EXPECT_FALSE(ret);
+}
+
+TEST_F(RtcIndexerTest, TestReset) {
+ // Without setting anything this indexer should behave exactly as the
+ // incremental indexer for the getNextSuffix()
+ testIncrement(indexer_);
+
+ // Reset the indexer
+ indexer_.reset();
+
+ // Now it should startfrom zero again
+ for (uint32_t i = 0; i < 4096; i++) {
+ auto index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+}
+
+TEST_F(RtcIndexerTest, TestGetNextSuffix) {
+ // Without setting anything this indexer should behave exactly as the
+ // incremental indexer for the getNextSuffix()
+ testIncrement(indexer_);
+}
+
+TEST_F(RtcIndexerTest, TestGetNextReassemblySegment) {
+ // This indexer should not provide reassembly segments since they are not
+ // required for rtc
+ try {
+ indexer_.getNextReassemblySegment();
+ // We should not reach this point
+ FAIL() << "Exception expected here";
+ } catch (const errors::RuntimeException &exc) {
+ // OK correct exception
+ } catch (...) {
+ FAIL() << "Wrong exception thrown";
+ }
+}
+
+TEST_F(RtcIndexerTest, TestGetFinalSuffix) {
+ // Final suffix should be eqaul to LIMIT
+ ASSERT_EQ(indexer_.getFinalSuffix(), uint32_t(LIMIT));
+}
+
+TEST_F(RtcIndexerTest, TestJumpToIndex) { testJump(indexer_); }
+
+TEST_F(RtcIndexerTest, TestIsFinalSuffixDiscovered) {
+ // This method should always return true
+ EXPECT_TRUE(indexer_.isFinalSuffixDiscovered());
+}
+
+TEST_F(RtcIndexerTest, TestMaxLimit) {
+ // Once reached the LIMIT, this indexer should restart from 0
+
+ // Jump to max value for uint32_t
+ indexer_.jumpToIndex(LIMIT);
+ testIncrement(indexer_);
+}
+
+TEST_F(RtcIndexerTest, TestEnableFec) {
+ // Here we enable the FEC and we check we receive indexes for souece packets
+ // only
+ indexer_.enableFec(fec::FECType::RS_K1_N3);
+
+ // We did not set NFec, which should be zero. So we get only indexes for
+ // Source packets.
+
+ // With this FEC type we should get one source packet every 3 (0 . . 3 . . 6)
+ auto index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(0));
+
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(3));
+
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(6));
+
+ // Change FEC Type
+ indexer_.enableFec(fec::FECType::RS_K10_N30);
+
+ // With this FEC type we should get source packets from 7 to 9
+ for (uint32_t i = 7; i < 10; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+
+ // And then jump to 30
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, uint32_t(30));
+
+ // Let's now jump to a high value
+ indexer_.jumpToIndex(12365);
+ for (uint32_t i = 12365; i < 12369; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(index, i);
+ }
+}
+
+TEST_F(RtcIndexerTest, TestSetNFec) {
+ // Here we enable the FEC and we set a max of 20 fec packets
+ indexer_.enableFec(fec::FECType::RS_K10_N90);
+ indexer_.setNFec(20);
+
+ // We should get indexes up to 29
+ uint32_t index;
+ for (uint32_t i = 0; i < 30; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(i, index);
+ }
+
+ // Then it should jump to 90
+ for (uint32_t i = 90; i < 99; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_EQ(i, index);
+ }
+
+ // Let's set NFEC > 80
+ indexer_.setNFec(150);
+}
+
+TEST_F(RtcIndexerTest, TestSetNFecWithOffset) {
+ // Here we enable the FEC and we set a max of 20 fec packets
+ const constexpr uint32_t first_suffix = 7;
+ indexer_.setFirstSuffix(first_suffix);
+ indexer_.reset();
+ indexer_.enableFec(fec::FECType::RS_K16_N24);
+ indexer_.setNFec(8);
+
+ uint32_t index;
+ for (uint32_t i = first_suffix; i < 16 + first_suffix; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_FALSE(indexer_.isFec(index));
+ EXPECT_EQ(i, index);
+ }
+
+ for (uint32_t i = first_suffix + 16; i < 16 + 8 + first_suffix; i++) {
+ index = indexer_.getNextSuffix();
+ EXPECT_TRUE(indexer_.isFec(index));
+ EXPECT_EQ(i, index);
+ }
+}
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc
index 0a835db24..8853563b0 100644
--- a/libtransport/src/test/test_interest.cc
+++ b/libtransport/src/test/test_interest.cc
@@ -260,8 +260,3 @@ TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) {
} // 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/test/test_packet.cc b/libtransport/src/test/test_packet.cc
index 0ee140e2c..76ad352d6 100644
--- a/libtransport/src/test/test_packet.cc
+++ b/libtransport/src/test/test_packet.cc
@@ -47,10 +47,6 @@ class PacketForTest : public Packet {
throw errors::NotImplementedException();
}
- void setName(Name &&name) override {
- throw errors::NotImplementedException();
- }
-
void setLifetime(uint32_t lifetime) override {
throw errors::NotImplementedException();
}
@@ -1040,8 +1036,3 @@ TEST_F(PacketTest, TestSetGetTTL) {
} // namespace core
} // namespace transport
-
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/libtransport/src/test/test_transport_producer.cc b/libtransport/src/test/test_transport_producer.cc
deleted file mode 100644
index f711fb4bb..000000000
--- a/libtransport/src/test/test_transport_producer.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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 <random>
-
-#include "hicn/transport/interfaces/socket_producer.h"
-
-namespace transport {
-
-namespace interface {
-
-namespace {
-// The fixture for testing class Foo.
-class ProducerTest : public ::testing::Test {
- protected:
- ProducerTest() : name_("b001::123|321"), producer_() {
- // 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_;
- ProducerSocket producer_;
-};
-
-} // namespace
-
-TEST_F(ProducerTest, ProduceContent) { ASSERT_TRUE(true); }
-
-} // namespace interface
-
-} // 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/transport.config b/libtransport/src/transport.config
index a21175b8d..89db204d5 100644
--- a/libtransport/src/transport.config
+++ b/libtransport/src/transport.config
@@ -1,27 +1,61 @@
// Configuration for io_module
-
io_module = {
path = [];
name = "forwarder_module";
};
+// Configuration for forwarder io_module
forwarder = {
n_threads = 1;
-
- listeners = {
- l0 = {
- local_address = "127.0.0.1";
- local_port = 33436;
- }
- };
connectors = {
c0 = {
/* local_address and local_port are optional */
local_address = "127.0.0.1";
local_port = 33436;
- remote_address = "10.20.30.40";
+ remote_address = "127.0.0.1";
remote_port = 33436;
}
};
+
+ listeners = {
+ l0 = {
+ local_address = "127.0.0.1";
+ local_port = 33437;
+ }
+ };
+};
+
+// Logging
+log = {
+ // Log level (INFO (0), WARNING (1), ERROR (2), FATAL (3))
+ minloglevel = 0;
+
+ // Verbosity level for debug logs
+ v= 2;
+
+ // Log to stderr
+ logtostderr = true;
+
+ // Get fancy colored logs
+ colorlogtostderr = true;
+
+ // Log messages above this level also to stderr
+ stderrthreshold = 2;
+
+ // Set log prefix for each line log
+ log_prefix = true;
+
+ // Log dir
+ log_dir = "/tmp";
+
+ // Log only specific modules.
+ // Example: "membuf=2,rtc=3"
+ vmodule = "";
+
+ // Max log size in MB
+ max_log_size = 10;
+
+ // Log rotation
+ stop_logging_if_full_disk = true;
}; \ No newline at end of file
diff --git a/libtransport/src/utils/CMakeLists.txt b/libtransport/src/utils/CMakeLists.txt
index 1a23459b5..a85ab16bf 100644
--- a/libtransport/src/utils/CMakeLists.txt
+++ b/libtransport/src/utils/CMakeLists.txt
@@ -11,8 +11,6 @@
# 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
diff --git a/libtransport/src/utils/content_store.cc b/libtransport/src/utils/content_store.cc
index c5cb91149..8ae7fd4d4 100644
--- a/libtransport/src/utils/content_store.cc
+++ b/libtransport/src/utils/content_store.cc
@@ -13,10 +13,10 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/interest.h>
#include <hicn/transport/core/name.h>
-#include <hicn/transport/utils/log.h>
#include <utils/content_store.h>
namespace utils {
@@ -36,9 +36,9 @@ void ContentStore::insert(
if (TRANSPORT_EXPECT_FALSE(content_store_hash_table_.size() !=
fifo_list_.size())) {
- TRANSPORT_LOGW("Inconsistent size!!!!");
- TRANSPORT_LOGW("Hash Table: %zu |||| FIFO List: %zu",
- content_store_hash_table_.size(), fifo_list_.size());
+ LOG(WARNING) << "Inconsistent size!!!!";
+ LOG(WARNING) << "Hash Table: " << content_store_hash_table_.size()
+ << " |||| FIFO List: " << fifo_list_.size();
}
if (content_store_hash_table_.size() >= max_content_store_size_) {
@@ -59,11 +59,11 @@ void ContentStore::insert(
ObjectTimeEntry(content_object, std::chrono::steady_clock::now()), pos);
}
-std::shared_ptr<ContentObject> ContentStore::find(const Interest &interest) {
+std::shared_ptr<ContentObject> ContentStore::find(const Name &name) {
utils::SpinLock::Acquire locked(cs_mutex_);
std::shared_ptr<ContentObject> ret = empty_reference_;
- auto it = content_store_hash_table_.find(interest.getName());
+ auto it = content_store_hash_table_.find(name);
if (it != content_store_hash_table_.end()) {
auto content_lifetime = it->second.first.first->getLifetime();
auto time_passed_since_creation =
@@ -108,13 +108,11 @@ void ContentStore::printContent() {
for (auto &item : content_store_hash_table_) {
if (item.second.first.first->getPayloadType() ==
transport::core::PayloadType::MANIFEST) {
- TRANSPORT_LOGI("Manifest: %s",
- item.second.first.first->getName().toString().c_str());
+ LOG(INFO) << "Manifest: " << item.second.first.first->getName();
} else {
- TRANSPORT_LOGI("Data Packet: %s",
- item.second.first.first->getName().toString().c_str());
+ LOG(INFO) << "Data Packet: " << item.second.first.first->getName();
}
}
}
-} // end namespace utils \ No newline at end of file
+} // end namespace utils
diff --git a/libtransport/src/utils/content_store.h b/libtransport/src/utils/content_store.h
index 56cd2abb6..abe5e7f6c 100644
--- a/libtransport/src/utils/content_store.h
+++ b/libtransport/src/utils/content_store.h
@@ -52,7 +52,7 @@ class ContentStore {
void insert(const std::shared_ptr<ContentObject> &content_object);
- std::shared_ptr<ContentObject> find(const Interest &interest);
+ std::shared_ptr<ContentObject> find(const Name &name);
void erase(const Name &exact_name);
@@ -73,4 +73,4 @@ class ContentStore {
mutable utils::SpinLock cs_mutex_;
};
-} // end namespace utils \ No newline at end of file
+} // end namespace utils
diff --git a/libtransport/src/utils/daemonizator.cc b/libtransport/src/utils/daemonizator.cc
index bc7bae700..6cb7d16ba 100644
--- a/libtransport/src/utils/daemonizator.cc
+++ b/libtransport/src/utils/daemonizator.cc
@@ -14,9 +14,9 @@
*/
#ifndef _WIN32
+#include <glog/logging.h>
#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>
@@ -36,7 +36,7 @@ void Daemonizator::daemonize(bool close_fds) {
// PARENT PROCESS. Need to kill it.
if (process_id > 0) {
- TRANSPORT_LOGE("Process id of child process %d", process_id);
+ LOG(ERROR) << "Process id of child process " << process_id;
// return success in exit status
exit(EXIT_SUCCESS);
}
diff --git a/libtransport/src/utils/epoll_event_reactor.cc b/libtransport/src/utils/epoll_event_reactor.cc
index eb8c65352..457727bbe 100644
--- a/libtransport/src/utils/epoll_event_reactor.cc
+++ b/libtransport/src/utils/epoll_event_reactor.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <hicn/transport/utils/branch_prediction.h>
#include <signal.h>
#include <unistd.h>
@@ -30,7 +31,7 @@ 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);
+ LOG(ERROR) << "invalid fd " << fd;
return -1;
}
@@ -41,7 +42,7 @@ int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) {
if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &evt) <
0)) {
- TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
return -1;
}
@@ -50,7 +51,7 @@ int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) {
int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) {
if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
- TRANSPORT_LOGE("invalid fd %d", fd);
+ LOG(ERROR) << "invalid fd " << fd;
return -1;
}
@@ -61,7 +62,7 @@ int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) {
if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) <
0)) {
- TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
return -1;
}
@@ -72,7 +73,7 @@ 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);
+ LOG(ERROR) << "invalid fd " << fd;
return -1;
}
@@ -81,7 +82,7 @@ int EpollEventReactor::delFileDescriptor(int fd) {
if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &evt) <
0)) {
- TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+ LOG(ERROR) << "epoll_ctl: " << strerror(errno) << " fd " << fd;
return -1;
}
@@ -106,7 +107,7 @@ void EpollEventReactor::runEventLoop(int timeout) {
en = epoll_pwait(epoll_fd_, evt, 128, timeout, &sigset);
if (TRANSPORT_EXPECT_FALSE(en < 0)) {
- TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+ LOG(ERROR) << "epoll_pwait: " << strerror(errno);
if (errno == EINTR) {
continue;
} else {
@@ -122,7 +123,7 @@ void EpollEventReactor::runEventLoop(int timeout) {
}
if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
- TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+ LOG(ERROR) << "unexpected event. fd " << evt[i].data.fd;
} else {
{
utils::SpinLock::Acquire locked(event_callback_map_lock_);
@@ -138,7 +139,7 @@ void EpollEventReactor::runEventLoop(int timeout) {
}
}
} else {
- TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+ LOG(ERROR) << "unexpected event. fd " << evt[i].data.fd;
}
}
}
@@ -159,7 +160,7 @@ void EpollEventReactor::runOneEvent() {
en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset);
if (TRANSPORT_EXPECT_FALSE(en < 0)) {
- TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+ LOG(ERROR) << "epoll_pwait: " << strerror(errno);
return;
}
@@ -170,7 +171,7 @@ void EpollEventReactor::runOneEvent() {
}
if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
- TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+ LOG(ERROR) << "unexpected event. fd " << evt.data.fd;
} else {
{
utils::SpinLock::Acquire locked(event_callback_map_lock_);
@@ -180,7 +181,7 @@ void EpollEventReactor::runOneEvent() {
callback(evt);
}
} else {
- TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+ LOG(ERROR) << "unexpected event. fd " << evt.data.fd;
}
}
diff --git a/libtransport/src/utils/fd_deadline_timer.h b/libtransport/src/utils/fd_deadline_timer.h
index 38396e027..22c13a763 100644
--- a/libtransport/src/utils/fd_deadline_timer.h
+++ b/libtransport/src/utils/fd_deadline_timer.h
@@ -16,7 +16,6 @@
#pragma once
#include <hicn/transport/errors/runtime_exception.h>
-#include <hicn/transport/utils/log.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <utils/deadline_timer.h>
@@ -58,7 +57,7 @@ class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> {
std::error_code ec;
if (read(event.data.fd, &s, sizeof(s)) == -1) {
- TRANSPORT_LOGE("Read error!!");
+ LOG(ERROR) << "Read error!!";
}
if (!(event.events & EPOLLIN)) {
diff --git a/libtransport/src/utils/log.cc b/libtransport/src/utils/log.cc
index 27dd3f541..755d5bafa 100644
--- a/libtransport/src/utils/log.cc
+++ b/libtransport/src/utils/log.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,1391 +13,79 @@
* 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.
- */
-
-#if defined(__ANDROID__)
-#define TRANSPORT_LOG_USE_ANDROID_LOG 1
-#define ANDROID_TAG "HicnTransport"
-#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
+#define GLOG_CUSTOM_PREFIX_SUPPORT 1
+#include <glog/logging.h>
+#undef GLOG_CUSTOM_PREFIX_SUPPORT
-#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 <core/global_configuration.h>
+#include <hicn/transport/config.h>
#include <hicn/transport/utils/log.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#if defined(_WIN32) || defined(_WIN64)
-#include <windows.h>
-#else
-#include <sys/time.h>
-#include <unistd.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;
+#include <iomanip>
+#include <iostream>
+#include <libconfig.h++>
+
+namespace utils {
+
+#define _(class_name, macro_name) \
+ std::ostream &CLASS_NAME(class_name)::getStream() { return macro_name; }
+foreach_log_level
+#undef _
+
+ class LogConfiguration {
+ static constexpr char log_config_section[] = "log";
+#define LOG_NAME \
+ "Libhicntransport-" HICNTRANSPORT_VERSION_MAJOR \
+ "." HICNTRANSPORT_VERSION_MINOR "." HICNTRANSPORT_VERSION_REVISION
+ static constexpr char log_name[] = LOG_NAME;
+
+#define foreach_log_config \
+ _(bool, logtostderr, true) \
+ _(bool, alsologtostderr, false) \
+ _(bool, colorlogtostderr, true) \
+ _(int32_t, stderrthreshold, 2) \
+ _(int32_t, minloglevel, 0) \
+ _(bool, log_prefix, true) \
+ _(std::string, log_dir, "") \
+ _(int32_t, v, 1) \
+ _(std::string, vmodule, "") \
+ _(int32_t, max_log_size, 5) \
+ _(bool, stop_logging_if_full_disk, true)
+
+ public:
+ LogConfiguration() {
+ auto &conf = transport::core::GlobalConfiguration::getInstance();
+
+ using namespace std::placeholders;
+ conf.registerConfigurationParser(
+ log_config_section,
+ std::bind(&LogConfiguration::parseLogConfiguration, this, _1, _2));
+ }
+
+ private:
+ void parseLogConfiguration(const libconfig::Setting &log_config,
+ std::error_code &ec) {
+#define _(type, name, default) \
+ type _##name = default; \
+ \
+ if (log_config.exists(#name)) { \
+ log_config.lookupValue(#name, _##name); \
+ VLOG(2) << "Setting log config " << #name << " to " << _##name; \
+ \
+ FLAGS_##name = _##name; \
+ } else { \
+ VLOG(2) << "Log config " << #name << " do not exists"; \
+ }
+ foreach_log_config
+#undef _
+
+ google::InitGoogleLogging(log_name);
}
- __android_log_print(android_lvl(msg->lvl), ANDROID_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);
-}
+constexpr char LogConfiguration::log_config_section[];
+constexpr char LogConfiguration::log_name[];
-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);
-}
+LogConfiguration log_conf = LogConfiguration();
-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
+} // namespace utils
diff --git a/libtransport/src/utils/min_filter.h b/libtransport/src/utils/min_filter.h
index f1aaea7a8..092555ce0 100644
--- a/libtransport/src/utils/min_filter.h
+++ b/libtransport/src/utils/min_filter.h
@@ -15,9 +15,6 @@
#pragma once
-#include <hicn/transport/portability/portability.h>
-#include <hicn/transport/utils/log.h>
-
#include <deque>
#include <iostream>
#include <set>
@@ -34,7 +31,7 @@ class MinFilter {
std::size_t size() { return by_arrival_.size(); }
template <typename R>
- TRANSPORT_ALWAYS_INLINE void pushBack(R&& value) {
+ void pushBack(R&& value) {
if (by_arrival_.size() >= size_) {
by_order_.erase(by_arrival_.back());
by_arrival_.pop_back();
@@ -43,14 +40,14 @@ class MinFilter {
by_arrival_.push_front(by_order_.insert(std::forward<R>(value)));
}
- TRANSPORT_ALWAYS_INLINE void clear() {
+ void clear() {
by_arrival_.clear();
by_order_.clear();
}
- TRANSPORT_ALWAYS_INLINE const T& begin() { return *by_order_.cbegin(); }
+ const T& begin() { return *by_order_.cbegin(); }
- TRANSPORT_ALWAYS_INLINE const T& rBegin() { return *by_order_.crbegin(); }
+ const T& rBegin() { return *by_order_.crbegin(); }
private:
std::multiset<T> by_order_;
diff --git a/libtransport/src/utils/suffix_strategy.h b/libtransport/src/utils/suffix_strategy.h
index 6c4dd2785..ee016308e 100644
--- a/libtransport/src/utils/suffix_strategy.h
+++ b/libtransport/src/utils/suffix_strategy.h
@@ -33,6 +33,8 @@ class SuffixStrategy {
virtual ~SuffixStrategy() = default;
+ virtual uint32_t checkNextSuffix() = 0;
+
virtual uint32_t getNextSuffix() = 0;
virtual uint32_t getFinalSuffix() { return final_suffix_; }
@@ -43,8 +45,12 @@ class SuffixStrategy {
}
}
+ virtual uint32_t checkNextManifestSuffix() = 0;
+
virtual uint32_t getNextManifestSuffix() = 0;
+ virtual uint32_t checkNextContentSuffix() = 0;
+
virtual uint32_t getNextContentSuffix() = 0;
virtual void reset(uint32_t offset = 0) = 0;
@@ -74,15 +80,27 @@ class IncrementalSuffixStrategy : public SuffixStrategy {
: SuffixStrategy(NextSegmentCalculationStrategy::INCREMENTAL),
next_suffix_(start_offset) {}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextSuffix() override {
+ return next_suffix_;
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override {
incrementTotalCount();
return next_suffix_++;
}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextContentSuffix() override {
+ return checkNextSuffix();
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override {
return getNextSuffix();
}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextManifestSuffix() override {
+ return checkNextSuffix();
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override {
return getNextSuffix();
}
@@ -112,17 +130,30 @@ class CapacityBasedSuffixStrategy : public SuffixStrategy {
segments_in_manifest_(manifest_capacity),
current_manifest_iteration_(0) {}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextSuffix() override {
+ return next_suffix_;
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextSuffix() override {
incrementTotalCount();
return next_suffix_++;
}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextContentSuffix() override {
+ return next_suffix_ % segments_in_manifest_ == 0 ? next_suffix_
+ : (next_suffix_ + 1);
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextContentSuffix() override {
incrementTotalCount();
return next_suffix_ % segments_in_manifest_ == 0 ? next_suffix_++
: ++next_suffix_;
}
+ TRANSPORT_ALWAYS_INLINE std::uint32_t checkNextManifestSuffix() override {
+ return (current_manifest_iteration_ + 1) * (segments_in_manifest_ + 1);
+ }
+
TRANSPORT_ALWAYS_INLINE std::uint32_t getNextManifestSuffix() override {
incrementTotalCount();
return (current_manifest_iteration_++) * (segments_in_manifest_ + 1);