aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/test')
-rw-r--r--libtransport/src/test/CMakeLists.txt13
-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/packet_samples.h58
-rw-r--r--libtransport/src/test/test_auth.cc110
-rw-r--r--libtransport/src/test/test_consumer_producer_rtc.cc176
-rw-r--r--libtransport/src/test/test_core_manifest.cc44
-rw-r--r--libtransport/src/test/test_event_thread.cc106
-rw-r--r--libtransport/src/test/test_fec_reedsolomon.cc291
-rw-r--r--libtransport/src/test/test_interest.cc267
-rw-r--r--libtransport/src/test/test_packet.cc1047
11 files changed, 2405 insertions, 17 deletions
diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt
index 19e59c7e1..dd3d1d923 100644
--- a/libtransport/src/test/CMakeLists.txt
+++ b/libtransport/src/test/CMakeLists.txt
@@ -14,14 +14,15 @@
include(BuildMacros)
list(APPEND TESTS
+ test_auth
+ test_consumer_producer_rtc
test_core_manifest
- test_transport_producer
+ test_event_thread
+ test_fec_reedsolomon
+ test_interest
+ test_packet
)
-if (${LIBTRANSPORT_SHARED} MATCHES ".*-memif.*")
- set(LINK_FLAGS "-Wl,-unresolved-symbols=ignore-in-shared-libs")
-endif()
-
foreach(test ${TESTS})
build_executable(${test}
NO_INSTALL
@@ -35,4 +36,4 @@ foreach(test ${TESTS})
)
add_test_internal(${test})
-endforeach() \ No newline at end of file
+endforeach()
diff --git a/libtransport/src/test/fec_reed_solomon.cc b/libtransport/src/test/fec_reed_solomon.cc
new file mode 100644
index 000000000..36543c531
--- /dev/null
+++ b/libtransport/src/test/fec_reed_solomon.cc
@@ -0,0 +1,154 @@
+/*
+ * 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
new file mode 100644
index 000000000..e7745bae5
--- /dev/null
+++ b/libtransport/src/test/fec_rely.cc
@@ -0,0 +1,156 @@
+/*
+ * 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/packet_samples.h b/libtransport/src/test/packet_samples.h
new file mode 100644
index 000000000..e98d06a18
--- /dev/null
+++ b/libtransport/src/test/packet_samples.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#define TCP_PROTO 0x06
+#define ICMP_PROTO 0x01
+#define ICMP6_PROTO 0x3a
+
+#define IPV6_HEADER(next_header, payload_length) \
+ 0x60, 0x00, 0x00, 0x00, 0x00, payload_length, next_header, 0x40, 0xb0, 0x06, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xcd, 0xab, \
+ 0xcd, 0xef, 0xb0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xca
+
+#define IPV4_HEADER(next_header, payload_length) \
+ 0x45, 0x02, 0x00, payload_length + 20, 0x47, 0xc4, 0x40, 0x00, 0x25, \
+ next_header, 0x6e, 0x76, 0x03, 0x7b, 0xd9, 0xd0, 0xc0, 0xa8, 0x01, 0x5c
+
+#define TCP_HEADER(flags) \
+ 0x12, 0x34, 0x43, 0x21, 0x00, 0x00, 0x00, 0x01, 0xb2, 0x8c, 0x03, 0x1f, \
+ 0x80, flags, 0x00, 0x0a, 0xb9, 0xbb, 0x00, 0x00
+
+#define PAYLOAD \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x20, 0x00, 0x00
+
+#define PAYLOAD_SIZE 12
+
+#define ICMP_ECHO_REQUEST \
+ 0x08, 0x00, 0x87, 0xdb, 0x38, 0xa7, 0x00, 0x05, 0x60, 0x2b, 0xc2, 0xcb, \
+ 0x00, 0x02, 0x29, 0x7c, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, \
+ 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, \
+ 0x34, 0x35, 0x36, 0x37
+
+#define ICMP6_ECHO_REQUEST \
+ 0x80, 0x00, 0x86, 0x3c, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, \
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, \
+ 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33
+
+#define AH_HEADER \
+ 0x00, (128 >> 2), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff --git a/libtransport/src/test/test_auth.cc b/libtransport/src/test/test_auth.cc
new file mode 100644
index 000000000..976981cce
--- /dev/null
+++ b/libtransport/src/test/test_auth.cc
@@ -0,0 +1,110 @@
+/*
+ * 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/auth/crypto_hash_type.h>
+#include <hicn/transport/auth/identity.h>
+#include <hicn/transport/auth/signer.h>
+#include <hicn/transport/auth/verifier.h>
+#include <hicn/transport/core/content_object.h>
+
+namespace transport {
+namespace auth {
+
+namespace {
+class AuthTest : public ::testing::Test {
+ protected:
+ const std::string PASSPHRASE = "hunter2";
+
+ AuthTest() = default;
+ ~AuthTest() {}
+ void SetUp() override {}
+ void TearDown() override {}
+};
+} // namespace
+
+TEST_F(AuthTest, VoidVerifier) {
+ // Create a content object
+ core::ContentObject packet(HF_INET6_TCP_AH);
+
+ // Fill it with bogus data
+ uint8_t buffer[256] = {0};
+ packet.appendPayload(buffer, 256);
+
+ // 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);
+}
+
+TEST_F(AuthTest, RSAVerifier) {
+ // 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
+ core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
+
+ // Fill it with bogus data
+ uint8_t buffer[256] = {0};
+ packet.appendPayload(buffer, 256);
+
+ // Sign the packet
+ signer->signPacket(&packet);
+
+ // Create the RSA verifier
+ PARCKey *key = parcSigner_CreatePublicKey(signer->getParcSigner());
+ std::shared_ptr<Verifier> verifier =
+ std::make_shared<AsymmetricVerifier>(key);
+
+ 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);
+
+ // Release PARC objects
+ parcKey_Release(&key);
+}
+
+TEST_F(AuthTest, HMACVerifier) {
+ // Create the HMAC signer from a passphrase
+ std::shared_ptr<Signer> 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);
+
+ // Sign the packet
+ signer->signPacket(&packet);
+
+ // Create the HMAC verifier
+ 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);
+}
+
+} // namespace auth
+} // namespace transport
diff --git a/libtransport/src/test/test_consumer_producer_rtc.cc b/libtransport/src/test/test_consumer_producer_rtc.cc
new file mode 100644
index 000000000..87385971a
--- /dev/null
+++ b/libtransport/src/test/test_consumer_producer_rtc.cc
@@ -0,0 +1,176 @@
+/*
+ * 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/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 {
+
+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_),
+ stop_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 setStopTimer() {
+ using namespace std::chrono;
+ stop_timer_.expires_from_now(seconds(unsigned(10)));
+ stop_timer_.async_wait(
+ std::bind(&ConsumerProducerTest::stop, this, std::placeholders::_1));
+ }
+
+ void produceRTCPacket(const std::error_code &ec) {
+ if (ec) {
+ io_service_.stop();
+ }
+
+ producer_.produceDatagram(consumer_name_, payload_, payload_size);
+ packets_sent_++;
+ setTimer();
+ }
+
+ void stop(const std::error_code &ec) {
+ rtc_timer_.cancel();
+ producer_.stop();
+ consumer_.stop();
+ }
+
+ // 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_++;
+ std::cout << "Received something" << std::endl;
+ }
+
+ asio::io_service io_service_;
+ asio::steady_timer rtc_timer_;
+ asio::steady_timer stop_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_);
+ setStopTimer();
+
+ io_service_.run();
+
+ std::cout << "Packet received: " << packets_received_ << std::endl;
+ std::cout << "Packet sent: " << packets_sent_ << std::endl;
+}
+
+} // 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 faf17dcf0..f98147d43 100644
--- a/libtransport/src/test/test_core_manifest.cc
+++ b/libtransport/src/test/test_core_manifest.cc
@@ -16,7 +16,8 @@
#include <core/manifest_format_fixed.h>
#include <core/manifest_inline.h>
#include <gtest/gtest.h>
-#include <hicn/transport/security/crypto_hash_type.h>
+#include <hicn/transport/auth/crypto_hash_type.h>
+#include <test/packet_samples.h>
#include <climits>
#include <random>
@@ -72,6 +73,27 @@ class ManifestTest : public ::testing::Test {
} // namespace
+TEST_F(ManifestTest, MoveConstructor) {
+ // Create content object with manifest in payload
+ ContentObject co(HF_INET6_TCP_AH, 128);
+ co.appendPayload(&manifest_payload[0], manifest_payload.size());
+ uint8_t buffer[256];
+ co.appendPayload(buffer, 256);
+
+ // Copy packet payload
+ uint8_t packet[1500];
+ auto length = co.getPayload()->length();
+ std::memcpy(packet, co.getPayload()->data(), length);
+
+ // Create manifest
+ ContentObjectManifest m(std::move(co));
+
+ // Check manifest payload is exactly the same of content object
+ ASSERT_EQ(length, m.getPayload()->length());
+ auto ret = std::memcmp(packet, m.getPayload()->data(), length);
+ ASSERT_EQ(ret, 0);
+}
+
TEST_F(ManifestTest, SetLastManifest) {
manifest1_.clear();
@@ -102,9 +124,9 @@ TEST_F(ManifestTest, SetManifestType) {
TEST_F(ManifestTest, SetHashAlgorithm) {
manifest1_.clear();
- utils::CryptoHashType hash1 = utils::CryptoHashType::SHA_512;
- utils::CryptoHashType hash2 = utils::CryptoHashType::CRC32C;
- utils::CryptoHashType hash3 = utils::CryptoHashType::SHA_256;
+ auth::CryptoHashType hash1 = auth::CryptoHashType::SHA_512;
+ auth::CryptoHashType hash2 = auth::CryptoHashType::CRC32C;
+ auth::CryptoHashType hash3 = auth::CryptoHashType::SHA_256;
manifest1_.setHashAlgorithm(hash1);
auto type_returned1 = manifest1_.getHashAlgorithm();
@@ -161,7 +183,7 @@ TEST_F(ManifestTest, SetSuffixList) {
std::uniform_int_distribution<uint64_t> idis(
0, std::numeric_limits<uint32_t>::max());
- auto entries = new std::pair<uint32_t, utils::CryptoHash>[3];
+ auto entries = new std::pair<uint32_t, auth::CryptoHash>[3];
uint32_t suffixes[3];
std::vector<unsigned char> data[3];
@@ -170,8 +192,8 @@ TEST_F(ManifestTest, SetSuffixList) {
std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe));
suffixes[i] = idis(eng);
entries[i] = std::make_pair(
- suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(),
- utils::CryptoHashType::SHA_256));
+ suffixes[i], auth::CryptoHash(data[i].data(), data[i].size(),
+ auth::CryptoHashType::SHA_256));
manifest1_.addSuffixHash(entries[i].first, entries[i].second);
}
@@ -186,9 +208,9 @@ TEST_F(ManifestTest, SetSuffixList) {
// for (auto & item : manifest1_.getSuffixList()) {
// auto hash = manifest1_.getHash(suffixes[i]);
- // cond = utils::CryptoHash::compareBinaryDigest(hash,
- // entries[i].second.getDigest<uint8_t>().data(),
- // entries[i].second.getType());
+ // cond = auth::CryptoHash::compareBinaryDigest(hash,
+ // entries[i].second.getDigest<uint8_t>().data(),
+ // entries[i].second.getType());
// ASSERT_TRUE(cond);
// i++;
// }
@@ -205,4 +227,4 @@ TEST_F(ManifestTest, SetSuffixList) {
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_event_thread.cc b/libtransport/src/test/test_event_thread.cc
new file mode 100644
index 000000000..e66b49f10
--- /dev/null
+++ b/libtransport/src/test/test_event_thread.cc
@@ -0,0 +1,106 @@
+/*
+ * 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/utils/event_thread.h>
+
+#include <cmath>
+
+namespace utils {
+
+namespace {
+
+class EventThreadTest : public ::testing::Test {
+ protected:
+ EventThreadTest() : event_thread_() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~EventThreadTest() {
+ // 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).
+ }
+
+ utils::EventThread event_thread_;
+};
+
+double average(const unsigned long samples[], int size) {
+ double sum = 0;
+
+ for (int i = 0; i < size; i++) {
+ sum += samples[i];
+ }
+
+ return sum / size;
+}
+
+double stdDeviation(const unsigned long samples[], int size) {
+ double avg = average(samples, size);
+ double var = 0;
+
+ for (int i = 0; i < size; i++) {
+ var += (samples[i] - avg) * (samples[i] - avg);
+ }
+
+ return sqrt(var / size);
+}
+
+} // namespace
+
+TEST_F(EventThreadTest, SchedulingDelay) {
+ using namespace std::chrono;
+ const size_t size = 1000000;
+ std::vector<unsigned long> samples(size);
+
+ for (unsigned int i = 0; i < size; i++) {
+ auto t0 = steady_clock::now();
+ event_thread_.add([t0, &samples, i]() {
+ auto t1 = steady_clock::now();
+ samples[i] = duration_cast<nanoseconds>(t1 - t0).count();
+ });
+ }
+
+ event_thread_.stop();
+
+ auto avg = average(&samples[0], size);
+ auto sd = stdDeviation(&samples[0], size);
+ (void)sd;
+
+ // Expect average to be less that 1 ms
+ EXPECT_LT(avg, 1000000);
+}
+
+} // 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
new file mode 100644
index 000000000..3b10b7307
--- /dev/null
+++ b/libtransport/src/test/test_fec_reedsolomon.cc
@@ -0,0 +1,291 @@
+
+/*
+ * 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/rs.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/global_object_pool.h>
+
+#include <algorithm>
+#include <iostream>
+#include <random>
+
+namespace transport {
+namespace core {
+
+double ReedSolomonTest(int k, int n, int size) {
+ fec::encoder encoder(k, n);
+ fec::decoder decoder(k, n);
+
+ std::vector<fec::buffer> tx_block(k);
+ std::vector<fec::buffer> rx_block(k);
+ int count = 0;
+ 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));
+ }
+ });
+
+ 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++;
+ }
+ }
+ });
+
+ do {
+ // Discard eventual packet appended in previous callback call
+ tx_block.erase(tx_block.begin() + k, tx_block.end());
+
+ // Initialization. Feed encoder with first k source packets
+ for (int i = 0; i < k; i++) {
+ // Get new buffer from pool
+ auto packet = packet_manager.getMemBuf();
+
+ // Let's append a bit less than size, so that the FEC class will take care
+ // of filling the rest with zeros
+ auto cur_size = size - (rand() % 100);
+
+ // Set payload, saving 2 bytes at the beginning of the buffer for encoding
+ // the length
+ packet->append(cur_size);
+ packet->trimStart(2);
+ 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);
+
+ // Store packet in tx buffer and clear rx buffer
+ tx_block[i] = std::move(packet);
+ }
+
+ // Create the repair packets
+ for (auto &tx : tx_block) {
+ encoder.consume(tx, tx->writableBuffer()[0]);
+ }
+
+ // Simulate transmission on lossy channel
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ std::vector<bool> losses(n, false);
+ for (int i = 0; i < n - k; i++) losses[i] = true;
+
+ int rxi = 0;
+ std::shuffle(losses.begin(), losses.end(),
+ std::default_random_engine(seed));
+ for (int i = 0; i < n && rxi < k; i++)
+ if (losses[i] == false) {
+ rx_block[rxi++] = tx_block[i];
+ if (i < k) {
+ // Source packet
+ decoder.consume(rx_block[rxi - 1], rx_block[rxi - 1]->data()[0]);
+ } else {
+ // Repair packet
+ decoder.consume(rx_block[rxi - 1]);
+ }
+ }
+
+ decoder.clear();
+ encoder.clear();
+ } while (++run < iterations);
+
+ return count;
+}
+
+void ReedSolomonMultiBlockTest(int n_sourceblocks) {
+ int k = 16;
+ int n = 24;
+ int size = 1000;
+
+ fec::encoder encoder(k, n);
+ fec::decoder decoder(k, n);
+
+ auto &packet_manager = PacketManager<>::getInstance();
+
+ std::vector<std::pair<fec::buffer, uint32_t>> tx_block;
+ std::vector<std::pair<fec::buffer, uint32_t>> rx_block;
+ int count = 0;
+ int i = 0;
+
+ // Receiver will receive packet for n_sourceblocks in a random order.
+ int total_packets = n * 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);
+ }
+
+ 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]));
+ }
+
+ // 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++; });
+
+ // Produce n * n_sourceblocks
+ // - ( k ) * n_sourceblocks source packets
+ // - (n - k) * n_sourceblocks symbols)
+ for (i = 0; i < total_packets; i++) {
+ // Get new buffer from pool
+ auto packet = packet_manager.getMemBuf();
+
+ // Let's append a bit less than size, so that the FEC class will take care
+ // of filling the rest with zeros
+ auto cur_size = size - (rand() % 100);
+
+ // Set payload, saving 2 bytes at the beginning of the buffer for encoding
+ // the length
+ packet->append(cur_size);
+ packet->trimStart(2);
+ 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);
+
+ // Store packet in tx buffer
+ tx_block.emplace_back(packet, i);
+
+ // Feed encoder with packet
+ encoder.consume(packet, i);
+ }
+
+ // Here rx_block must contains k * n_sourceblocks packets
+ EXPECT_EQ(size_t(tx_packets), size_t(rx_block.size()));
+
+ // Lets shuffle the rx_block before starting feeding the decoder.
+ std::shuffle(rx_block.begin(), rx_block.end(),
+ std::default_random_engine(seed));
+
+ for (auto &p : rx_block) {
+ int index = p.second % n;
+ if (index < k) {
+ // Source packet
+ decoder.consume(p.first, p.second);
+ } else {
+ // Repair packet
+ decoder.consume(p.first);
+ }
+ }
+
+ // Simple test to check we get all the source packets
+ 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);
+}
+
+TEST(ReedSolomonMultiBlockTest, RSMB10) {
+ int blocks = 10;
+ ReedSolomonMultiBlockTest(blocks);
+}
+
+TEST(ReedSolomonMultiBlockTest, RSMB100) {
+ int blocks = 100;
+ ReedSolomonMultiBlockTest(blocks);
+}
+
+TEST(ReedSolomonMultiBlockTest, RSMB1000) {
+ int blocks = 1000;
+ ReedSolomonMultiBlockTest(blocks);
+}
+
+int main(int argc, char **argv) {
+ srand(time(0));
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+} // namespace core
+} // namespace transport
diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc
new file mode 100644
index 000000000..0a835db24
--- /dev/null
+++ b/libtransport/src/test/test_interest.cc
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <test/packet_samples.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+// The fixture for testing class Foo.
+class InterestTest : public ::testing::Test {
+ protected:
+ InterestTest() : name_("b001::123|321"), interest_() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~InterestTest() {
+ // 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_;
+
+ Interest interest_;
+
+ std::vector<uint8_t> buffer_ = {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(TCP_PROTO, 20 + PAYLOAD_SIZE),
+ // ICMP6 echo request
+ TCP_HEADER(0x00),
+ // Payload
+ PAYLOAD};
+};
+
+void testFormatConstructor(Packet::Format format = HF_UNSPEC) {
+ try {
+ Interest interest(format, 0);
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown for " << format;
+ }
+}
+
+void testFormatConstructorException(Packet::Format format = HF_UNSPEC) {
+ try {
+ Interest interest(format, 0);
+ FAIL() << "We expected an exception here";
+ } catch (errors::MalformedPacketException &exc) {
+ // Ok right exception
+ } catch (...) {
+ FAIL() << "Wrong exception thrown";
+ }
+}
+
+} // namespace
+
+TEST_F(InterestTest, ConstructorWithFormat) {
+ /**
+ * Without arguments it should be format = HF_UNSPEC.
+ * We expect a crash.
+ */
+
+ testFormatConstructor(Packet::Format::HF_INET_TCP);
+ testFormatConstructor(Packet::Format::HF_INET6_TCP);
+ testFormatConstructorException(Packet::Format::HF_INET_ICMP);
+ testFormatConstructorException(Packet::Format::HF_INET6_ICMP);
+ testFormatConstructor(Packet::Format::HF_INET_TCP_AH);
+ testFormatConstructor(Packet::Format::HF_INET6_TCP_AH);
+ testFormatConstructorException(Packet::Format::HF_INET_ICMP_AH);
+ testFormatConstructorException(Packet::Format::HF_INET6_ICMP_AH);
+}
+
+TEST_F(InterestTest, ConstructorWithName) {
+ /**
+ * Without arguments it should be format = HF_UNSPEC.
+ * We expect a crash.
+ */
+ Name n("b001::1|123");
+
+ try {
+ Interest interest(n);
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown";
+ }
+}
+
+TEST_F(InterestTest, ConstructorWithBuffer) {
+ // Ensure buffer is interest
+ auto ret = Interest::isInterest(&buffer_[0]);
+ EXPECT_TRUE(ret);
+
+ // Create interest from buffer
+ try {
+ Interest interest(Interest::COPY_BUFFER, &buffer_[0], buffer_.size());
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown";
+ }
+
+ std::vector<uint8_t> buffer2{// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(ICMP6_PROTO, 60 + 44),
+ // ICMP6 echo request
+ TCP_HEADER(0x00),
+ // Payload
+ PAYLOAD};
+
+ // Ensure this throws an exception
+ try {
+ Interest interest(Interest::COPY_BUFFER, &buffer2[0], buffer2.size());
+ FAIL() << "We expected an exception here";
+ } catch (errors::MalformedPacketException &exc) {
+ // Ok right exception
+ } catch (...) {
+ FAIL() << "Wrong exception thrown";
+ }
+}
+
+TEST_F(InterestTest, SetGetName) {
+ // Create interest from buffer
+ Interest interest(Interest::COPY_BUFFER, &buffer_[0], buffer_.size());
+
+ // Get name
+ auto n = interest.getName();
+
+ // ensure name is b002::ca|1
+ Name n2("b002::ca|1");
+ auto ret = (n == n2);
+
+ EXPECT_TRUE(ret);
+
+ Name n3("b003::1234|1234");
+
+ // Change name to b003::1234|1234
+ interest.setName(n3);
+
+ // Check name was set
+ n = interest.getName();
+ ret = (n == n3);
+ EXPECT_TRUE(ret);
+}
+
+TEST_F(InterestTest, SetGetLocator) {
+ // Create interest from buffer
+ Interest interest(Interest::COPY_BUFFER, &buffer_[0], buffer_.size());
+
+ // Get locator
+ auto l = interest.getLocator();
+
+ ip_address_t address;
+ ip_address_pton("b006::ab:cdab:cdef", &address);
+ auto ret = !std::memcmp(&l, &address, sizeof(address));
+
+ EXPECT_TRUE(ret);
+
+ // Set different locator
+ ip_address_pton("2001::1234::4321::abcd::", &address);
+
+ // Set it on interest
+ interest.setLocator(address);
+
+ // Check it was set
+ l = interest.getLocator();
+ ret = !std::memcmp(&l, &address, sizeof(address));
+
+ EXPECT_TRUE(ret);
+}
+
+TEST_F(InterestTest, SetGetLifetime) {
+ // Create interest from buffer
+ Interest interest;
+ const constexpr uint32_t lifetime = 10000;
+
+ // Set lifetime
+ interest.setLifetime(lifetime);
+
+ // Get lifetime
+ auto l = interest.getLifetime();
+
+ // Ensure they are the same
+ EXPECT_EQ(l, lifetime);
+}
+
+TEST_F(InterestTest, HasManifest) {
+ // Create interest from buffer
+ Interest interest;
+
+ // Let's expect anexception here
+ try {
+ interest.setPayloadType(PayloadType::UNSPECIFIED);
+ FAIL() << "We expect an esception here";
+ } catch (errors::RuntimeException &exc) {
+ // Ok right exception
+ } catch (...) {
+ FAIL() << "Wrong exception thrown";
+ }
+
+ interest.setPayloadType(PayloadType::DATA);
+ EXPECT_FALSE(interest.hasManifest());
+
+ interest.setPayloadType(PayloadType::MANIFEST);
+ EXPECT_TRUE(interest.hasManifest());
+}
+
+TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) {
+ // Create interest from buffer
+ Interest interest;
+
+ // Appenad some suffixes, with some duplicates
+ interest.appendSuffix(1);
+ interest.appendSuffix(2);
+ interest.appendSuffix(5);
+ interest.appendSuffix(3);
+ interest.appendSuffix(4);
+ interest.appendSuffix(5);
+ interest.appendSuffix(5);
+ interest.appendSuffix(5);
+ interest.appendSuffix(5);
+ interest.appendSuffix(5);
+
+ // Encode them in wire format
+ interest.encodeSuffixes();
+
+ // Iterate over them. They should be in order and without repetitions
+ auto suffix = interest.firstSuffix();
+ auto n_suffixes = interest.numberOfSuffixes();
+
+ for (uint32_t i = 0; i < n_suffixes; i++) {
+ EXPECT_EQ(*(suffix + i), (i + 1));
+ }
+}
+
+} // 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
new file mode 100644
index 000000000..0ee140e2c
--- /dev/null
+++ b/libtransport/src/test/test_packet.cc
@@ -0,0 +1,1047 @@
+/*
+ * 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <test/packet_samples.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+/**
+ * Since packet is an abstract class, we derive a concrete class to be used for
+ * the test.
+ */
+class PacketForTest : public Packet {
+ public:
+ template <typename... Args>
+ PacketForTest(Args &&... args) : Packet(std::forward<Args>(args)...) {}
+
+ virtual ~PacketForTest() {}
+
+ const Name &getName() const override {
+ throw errors::NotImplementedException();
+ }
+
+ Name &getWritableName() override { throw errors::NotImplementedException(); }
+
+ void setName(const Name &name) override {
+ throw errors::NotImplementedException();
+ }
+
+ void setName(Name &&name) override {
+ throw errors::NotImplementedException();
+ }
+
+ void setLifetime(uint32_t lifetime) override {
+ throw errors::NotImplementedException();
+ }
+
+ uint32_t getLifetime() const override {
+ throw errors::NotImplementedException();
+ }
+
+ void setLocator(const ip_address_t &locator) override {
+ throw errors::NotImplementedException();
+ }
+
+ void resetForHash() override { throw errors::NotImplementedException(); }
+
+ ip_address_t getLocator() const override {
+ throw errors::NotImplementedException();
+ }
+};
+
+namespace {
+// The fixture for testing class Foo.
+class PacketTest : public ::testing::Test {
+ protected:
+ PacketTest()
+ : name_("b001::123|321"),
+ packet(Packet::COPY_BUFFER, &raw_packets_[HF_INET6_TCP][0],
+ raw_packets_[HF_INET6_TCP].size()) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~PacketTest() {
+ // 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_;
+
+ PacketForTest packet;
+
+ static std::map<Packet::Format, std::vector<uint8_t>> raw_packets_;
+
+ std::vector<uint8_t> payload = {
+ 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00,
+ // 0x00, 0x45, 0xa3,
+ // 0xd1, 0xf2, 0x2b,
+ // 0x94, 0x41, 0x22,
+ // 0xc9, 0x00, 0x00,
+ // 0x00, 0x44, 0xa3,
+ // 0xd1, 0xf2, 0x2b,
+ // 0x94, 0x41, 0x22,
+ // 0xc8
+ };
+};
+
+std::map<Packet::Format, std::vector<uint8_t>> PacketTest::raw_packets_ = {
+ {Packet::Format::HF_INET6_TCP,
+
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(TCP_PROTO, 20 + PAYLOAD_SIZE),
+ // TCP src=0x1234 dst=0x4321, seq=0x0001
+ TCP_HEADER(0x00),
+ // Payload
+ PAYLOAD}},
+
+ {Packet::Format::HF_INET_TCP,
+ {// IPv4 src=3.13.127.8, dst=192.168.1.92
+ IPV4_HEADER(TCP_PROTO, 20 + PAYLOAD_SIZE),
+ // TCP src=0x1234 dst=0x4321, seq=0x0001
+ TCP_HEADER(0x00),
+ // Other
+ PAYLOAD}},
+
+ {Packet::Format::HF_INET_ICMP,
+ {// IPv4 src=3.13.127.8, dst=192.168.1.92
+ IPV4_HEADER(ICMP_PROTO, 64),
+ // ICMP echo request
+ ICMP_ECHO_REQUEST}},
+
+ {Packet::Format::HF_INET6_ICMP,
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(ICMP6_PROTO, 60),
+ // ICMP6 echo request
+ ICMP6_ECHO_REQUEST}},
+
+ {Packet::Format::HF_INET6_TCP_AH,
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(TCP_PROTO, 20 + 44 + 128),
+ // ICMP6 echo request
+ TCP_HEADER(0x18),
+ // hICN AH header
+ AH_HEADER}},
+
+ {Packet::Format::HF_INET_TCP_AH,
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV4_HEADER(TCP_PROTO, 20 + 44 + 128),
+ // ICMP6 echo request
+ TCP_HEADER(0x18),
+ // hICN AH header
+ AH_HEADER}},
+
+ // XXX No flag defined in ICMP header to signal AH header.
+ {Packet::Format::HF_INET_ICMP_AH,
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV4_HEADER(ICMP_PROTO, 64 + 44),
+ // ICMP6 echo request
+ ICMP_ECHO_REQUEST,
+ // hICN AH header
+ AH_HEADER}},
+
+ {Packet::Format::HF_INET6_ICMP_AH,
+ {// IPv6 src=b001::ab:cdab:cdef, dst=b002::ca
+ IPV6_HEADER(ICMP6_PROTO, 60 + 44),
+ // ICMP6 echo request
+ ICMP6_ECHO_REQUEST,
+ // hICN AH header
+ AH_HEADER}},
+
+};
+
+void testFormatConstructor(Packet::Format format = HF_UNSPEC) {
+ try {
+ PacketForTest packet(format);
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown for " << format;
+ }
+}
+
+void testFormatAndAdditionalHeaderConstructor(Packet::Format format,
+ std::size_t additional_header) {
+ PacketForTest packet(format, additional_header);
+ // Packet length should be the one of the normal header + the
+ // additional_header
+
+ EXPECT_EQ(packet.headerSize(),
+ Packet::getHeaderSizeFromFormat(format) + additional_header);
+}
+
+void testRawBufferConstructor(std::vector<uint8_t> packet,
+ Packet::Format format) {
+ try {
+ // Try to construct packet from correct buffer
+ PacketForTest p(Packet::WRAP_BUFFER, &packet[0], packet.size(),
+ packet.size());
+
+ // Check format is expected one.
+ EXPECT_EQ(p.getFormat(), format);
+
+ // // Try the same using a MemBuf
+ // auto buf = utils::MemBuf::wrapBuffer(&packet[0], packet.size());
+ // buf->append(packet.size());
+ // PacketForTest p2(std::move(buf));
+
+ // EXPECT_EQ(p2.getFormat(), format);
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown";
+ }
+
+ try {
+ // Try to construct packet from wrong buffer
+
+ // Modify next header to 0
+ /* ipv6 */
+ packet[6] = 0x00;
+ /* ipv4 */
+ packet[9] = 0x00;
+ PacketForTest p(Packet::WRAP_BUFFER, &packet[0], packet.size(),
+ packet.size());
+
+ // Format should fallback to HF_UNSPEC
+ EXPECT_EQ(p.getFormat(), HF_UNSPEC);
+ } catch (...) {
+ FAIL() << "ERROR: Unexpected exception thrown.";
+ }
+}
+
+void getHeaderSizeFromBuffer(Packet::Format format,
+ std::vector<uint8_t> &packet,
+ std::size_t expected) {
+ auto header_size = PacketForTest::getHeaderSizeFromBuffer(format, &packet[0]);
+ EXPECT_EQ(header_size, expected);
+}
+
+void getHeaderSizeFromFormat(Packet::Format format, std::size_t expected) {
+ auto header_size = PacketForTest::getHeaderSizeFromFormat(format);
+ EXPECT_EQ(header_size, expected);
+}
+
+void getPayloadSizeFromBuffer(Packet::Format format,
+ std::vector<uint8_t> &packet,
+ std::size_t expected) {
+ auto payload_size =
+ PacketForTest::getPayloadSizeFromBuffer(format, &packet[0]);
+ EXPECT_EQ(payload_size, expected);
+}
+
+void getFormatFromBuffer(Packet::Format expected,
+ std::vector<uint8_t> &packet) {
+ auto format = PacketForTest::getFormatFromBuffer(&packet[0], packet.size());
+ EXPECT_EQ(format, expected);
+}
+
+void getHeaderSize(std::size_t expected, const PacketForTest &packet) {
+ auto size = packet.headerSize();
+ EXPECT_EQ(size, expected);
+}
+
+void testGetFormat(Packet::Format expected, const Packet &packet) {
+ auto format = packet.getFormat();
+ EXPECT_EQ(format, expected);
+}
+
+} // namespace
+
+TEST_F(PacketTest, ConstructorWithFormat) {
+ testFormatConstructor(Packet::Format::HF_INET_TCP);
+ testFormatConstructor(Packet::Format::HF_INET6_TCP);
+ testFormatConstructor(Packet::Format::HF_INET_ICMP);
+ testFormatConstructor(Packet::Format::HF_INET6_ICMP);
+ testFormatConstructor(Packet::Format::HF_INET_TCP_AH);
+ testFormatConstructor(Packet::Format::HF_INET6_TCP_AH);
+ testFormatConstructor(Packet::Format::HF_INET_ICMP_AH);
+ testFormatConstructor(Packet::Format::HF_INET6_ICMP_AH);
+}
+
+TEST_F(PacketTest, ConstructorWithFormatAndAdditionalHeader) {
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET_TCP, 123);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET6_TCP, 360);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET_ICMP, 21);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET6_ICMP, 444);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET_TCP_AH, 555);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET6_TCP_AH,
+ 321);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET_ICMP_AH,
+ 123);
+ testFormatAndAdditionalHeaderConstructor(Packet::Format::HF_INET6_ICMP_AH,
+ 44);
+}
+
+TEST_F(PacketTest, ConstructorWithNew) {
+ auto &_packet = raw_packets_[HF_INET6_TCP];
+ auto packet_ptr = new PacketForTest(Packet::WRAP_BUFFER, &_packet[0],
+ _packet.size(), _packet.size());
+ (void)packet_ptr;
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInet6Tcp) {
+ auto format = Packet::Format::HF_INET6_TCP;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInetTcp) {
+ auto format = Packet::Format::HF_INET_TCP;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInetIcmp) {
+ auto format = Packet::Format::HF_INET_ICMP;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInet6Icmp) {
+ auto format = Packet::Format::HF_INET6_ICMP;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInet6TcpAh) {
+ auto format = Packet::Format::HF_INET6_TCP_AH;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, ConstructorWithRawBufferInetTcpAh) {
+ auto format = Packet::Format::HF_INET_TCP_AH;
+ testRawBufferConstructor(raw_packets_[format], format);
+}
+
+TEST_F(PacketTest, MoveConstructor) {
+ PacketForTest p0(Packet::Format::HF_INET6_TCP);
+ PacketForTest p1(std::move(p0));
+ EXPECT_EQ(p0.getFormat(), Packet::Format::HF_UNSPEC);
+ EXPECT_EQ(p1.getFormat(), Packet::Format::HF_INET6_TCP);
+}
+
+TEST_F(PacketTest, TestGetHeaderSizeFromBuffer) {
+ getHeaderSizeFromBuffer(HF_INET6_TCP, raw_packets_[HF_INET6_TCP],
+ HICN_V6_TCP_HDRLEN);
+ getHeaderSizeFromBuffer(HF_INET_TCP, raw_packets_[HF_INET_TCP],
+ HICN_V4_TCP_HDRLEN);
+ getHeaderSizeFromBuffer(HF_INET6_ICMP, raw_packets_[HF_INET6_ICMP],
+ IPV6_HDRLEN + 4);
+ getHeaderSizeFromBuffer(HF_INET_ICMP, raw_packets_[HF_INET_ICMP],
+ IPV4_HDRLEN + 4);
+ getHeaderSizeFromBuffer(HF_INET6_TCP_AH, raw_packets_[HF_INET6_TCP_AH],
+ HICN_V6_TCP_AH_HDRLEN + 128);
+ getHeaderSizeFromBuffer(HF_INET_TCP_AH, raw_packets_[HF_INET_TCP_AH],
+ HICN_V4_TCP_AH_HDRLEN + 128);
+}
+
+TEST_F(PacketTest, TestGetHeaderSizeFromFormat) {
+ getHeaderSizeFromFormat(HF_INET6_TCP, HICN_V6_TCP_HDRLEN);
+ getHeaderSizeFromFormat(HF_INET_TCP, HICN_V4_TCP_HDRLEN);
+ getHeaderSizeFromFormat(HF_INET6_ICMP, IPV6_HDRLEN + 4);
+ getHeaderSizeFromFormat(HF_INET_ICMP, IPV4_HDRLEN + 4);
+ getHeaderSizeFromFormat(HF_INET6_TCP_AH, HICN_V6_TCP_AH_HDRLEN);
+ getHeaderSizeFromFormat(HF_INET_TCP_AH, HICN_V4_TCP_AH_HDRLEN);
+}
+
+TEST_F(PacketTest, TestGetPayloadSizeFromBuffer) {
+ getPayloadSizeFromBuffer(HF_INET6_TCP, raw_packets_[HF_INET6_TCP], 12);
+ getPayloadSizeFromBuffer(HF_INET_TCP, raw_packets_[HF_INET_TCP], 12);
+ getPayloadSizeFromBuffer(HF_INET6_ICMP, raw_packets_[HF_INET6_ICMP], 56);
+ getPayloadSizeFromBuffer(HF_INET_ICMP, raw_packets_[HF_INET_ICMP], 60);
+ getPayloadSizeFromBuffer(HF_INET6_TCP_AH, raw_packets_[HF_INET6_TCP_AH], 0);
+ getPayloadSizeFromBuffer(HF_INET_TCP_AH, raw_packets_[HF_INET_TCP_AH], 0);
+}
+
+TEST_F(PacketTest, TestIsInterest) {
+ auto ret = PacketForTest::isInterest(&raw_packets_[HF_INET6_TCP][0]);
+
+ EXPECT_TRUE(ret);
+}
+
+TEST_F(PacketTest, TestGetFormatFromBuffer) {
+ getFormatFromBuffer(HF_INET6_TCP, raw_packets_[HF_INET6_TCP]);
+ getFormatFromBuffer(HF_INET_TCP, raw_packets_[HF_INET_TCP]);
+ getFormatFromBuffer(HF_INET6_ICMP, raw_packets_[HF_INET6_ICMP]);
+ getFormatFromBuffer(HF_INET_ICMP, raw_packets_[HF_INET_ICMP]);
+ getFormatFromBuffer(HF_INET6_TCP_AH, raw_packets_[HF_INET6_TCP_AH]);
+ getFormatFromBuffer(HF_INET_TCP_AH, raw_packets_[HF_INET_TCP_AH]);
+}
+
+// TEST_F(PacketTest, TestReplace) {
+// PacketForTest packet(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_TCP][0],
+// raw_packets_[HF_INET6_TCP].size());
+
+// // Replace current packet with another one
+// packet.replace(&raw_packets_[HF_INET_TCP][0],
+// raw_packets_[HF_INET_TCP].size());
+
+// // Check new format
+// ASSERT_EQ(packet.getFormat(), HF_INET_TCP);
+// }
+
+TEST_F(PacketTest, TestPayloadSize) {
+ // Check payload size of existing packet
+ auto &_packet = raw_packets_[HF_INET6_TCP];
+ PacketForTest packet(Packet::WRAP_BUFFER, &_packet[0], _packet.size(),
+ _packet.size());
+
+ EXPECT_EQ(packet.payloadSize(), std::size_t(PAYLOAD_SIZE));
+
+ // Check for dynamic generated packet
+ std::string payload0(1024, 'X');
+
+ // Create the packet
+ PacketForTest packet2(HF_INET6_TCP);
+
+ // Payload size should now be zero
+ EXPECT_EQ(packet2.payloadSize(), std::size_t(0));
+
+ // Append payload 1 time
+ packet2.appendPayload((const uint8_t *)payload0.c_str(), payload0.size());
+
+ // size should now be 1024
+ EXPECT_EQ(packet2.payloadSize(), std::size_t(1024));
+
+ // Append second payload
+ std::string payload1(1024, 'X');
+ packet2.appendPayload((const uint8_t *)payload1.c_str(), payload1.size());
+
+ // Check size is 2048
+ EXPECT_EQ(packet2.payloadSize(), std::size_t(2048));
+
+ // Append Membuf
+ packet2.appendPayload(utils::MemBuf::copyBuffer(
+ (const uint8_t *)payload1.c_str(), payload1.size()));
+
+ // Check size is 3072
+ EXPECT_EQ(packet2.payloadSize(), std::size_t(3072));
+}
+
+TEST_F(PacketTest, TestHeaderSize) {
+ getHeaderSize(HICN_V6_TCP_HDRLEN,
+ PacketForTest(Packet::Format::HF_INET6_TCP));
+ getHeaderSize(HICN_V4_TCP_HDRLEN, PacketForTest(Packet::Format::HF_INET_TCP));
+ getHeaderSize(HICN_V6_ICMP_HDRLEN,
+ PacketForTest(Packet::Format::HF_INET6_ICMP));
+ getHeaderSize(HICN_V4_ICMP_HDRLEN,
+ PacketForTest(Packet::Format::HF_INET_ICMP));
+ getHeaderSize(HICN_V6_TCP_AH_HDRLEN,
+ PacketForTest(Packet::Format::HF_INET6_TCP_AH));
+ getHeaderSize(HICN_V4_TCP_AH_HDRLEN,
+ PacketForTest(Packet::Format::HF_INET_TCP_AH));
+}
+
+TEST_F(PacketTest, TestMemBufReference) {
+ // Create packet
+ auto &_packet = raw_packets_[HF_INET6_TCP];
+
+ // Packet was not created as a shared_ptr. If we try to get a membuf shared
+ // ptr we should get an exception.
+ // TODO test with c++ 17
+ // try {
+ // PacketForTest packet(&_packet[0], _packet.size());
+ // auto membuf_ref = packet.acquireMemBufReference();
+ // FAIL() << "The acquireMemBufReference() call should have throwed an "
+ // "exception!";
+ // } catch (const std::bad_weak_ptr &e) {
+ // // Ok
+ // } catch (...) {
+ // FAIL() << "Not expected exception.";
+ // }
+
+ auto packet_ptr = std::make_shared<PacketForTest>(
+ Packet::WRAP_BUFFER, &_packet[0], _packet.size(), _packet.size());
+ PacketForTest &packet = *packet_ptr;
+
+ // Acquire a reference to the membuf
+ auto membuf_ref = packet.acquireMemBufReference();
+
+ // Check refcount. It should be 2
+ EXPECT_EQ(membuf_ref.use_count(), 2);
+
+ // Now increment membuf references
+ Packet::MemBufPtr membuf = packet.acquireMemBufReference();
+
+ // Now reference count should be 2
+ EXPECT_EQ(membuf_ref.use_count(), 3);
+
+ // Copy again
+ Packet::MemBufPtr membuf2 = membuf;
+
+ // Now reference count should be 3
+ EXPECT_EQ(membuf_ref.use_count(), 4);
+}
+
+TEST_F(PacketTest, TestReset) {
+ // Check everything is ok
+ EXPECT_EQ(packet.getFormat(), HF_INET6_TCP);
+ EXPECT_EQ(packet.length(), raw_packets_[HF_INET6_TCP].size());
+ EXPECT_EQ(packet.headerSize(), HICN_V6_TCP_HDRLEN);
+ EXPECT_EQ(packet.payloadSize(), packet.length() - packet.headerSize());
+
+ // Reset the packet
+ packet.reset();
+
+ // Rerun test
+ EXPECT_EQ(packet.getFormat(), HF_UNSPEC);
+ EXPECT_EQ(packet.length(), std::size_t(0));
+ EXPECT_EQ(packet.headerSize(), std::size_t(0));
+ EXPECT_EQ(packet.payloadSize(), std::size_t(0));
+}
+
+TEST_F(PacketTest, TestAppendPayload) {
+ // Append payload with raw buffer
+ uint8_t raw_buffer[2048];
+ auto original_payload_length = packet.payloadSize();
+ packet.appendPayload(raw_buffer, 1024);
+
+ EXPECT_EQ(original_payload_length + 1024, packet.payloadSize());
+
+ for (int i = 0; i < 10; i++) {
+ // Append other payload 10 times
+ packet.appendPayload(raw_buffer, 1024);
+ EXPECT_EQ(original_payload_length + 1024 + (1024) * (i + 1),
+ packet.payloadSize());
+ }
+
+ // Append payload using membuf
+ packet.appendPayload(utils::MemBuf::copyBuffer(raw_buffer, 2048));
+ EXPECT_EQ(original_payload_length + 1024 + 1024 * 10 + 2048,
+ packet.payloadSize());
+
+ // Check the underlying MemBuf length is the expected one
+ utils::MemBuf *current = &packet;
+ size_t total = 0;
+ do {
+ total += current->length();
+ current = current->next();
+ } while (current != &packet);
+
+ EXPECT_EQ(total, packet.headerSize() + packet.payloadSize());
+
+ // LEt's try now to reset this packet
+ packet.reset();
+
+ // There should be no more bufferls left in the chain
+ EXPECT_EQ(&packet, packet.next());
+ EXPECT_EQ(packet.getFormat(), HF_UNSPEC);
+ EXPECT_EQ(packet.length(), std::size_t(0));
+ EXPECT_EQ(packet.headerSize(), std::size_t(0));
+ EXPECT_EQ(packet.payloadSize(), std::size_t(0));
+}
+
+TEST_F(PacketTest, GetPayload) {
+ // Append payload with raw buffer
+ uint8_t raw_buffer[2048];
+ auto original_payload_length = packet.payloadSize();
+ packet.appendPayload(raw_buffer, 2048);
+
+ // Get payload
+ auto payload = packet.getPayload();
+ // Check payload length is correct
+ utils::MemBuf *current = payload.get();
+ size_t total = 0;
+ do {
+ total += current->length();
+ current = current->next();
+ } while (current != payload.get());
+
+ ASSERT_EQ(total, packet.payloadSize());
+
+ // Linearize the payload
+ payload->gather(total);
+
+ // Check memory correspond
+ payload->trimStart(original_payload_length);
+ auto ret = memcmp(raw_buffer, payload->data(), 2048);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST_F(PacketTest, UpdateLength) {
+ auto original_payload_size = packet.payloadSize();
+
+ // Add some fake payload without using the API
+ packet.append(200);
+
+ // payloadSize does not know about the new payload, yet
+ EXPECT_EQ(packet.payloadSize(), original_payload_size);
+
+ // Let's now update the packet length
+ packet.updateLength();
+
+ // Now payloadSize knows
+ EXPECT_EQ(packet.payloadSize(), std::size_t(original_payload_size + 200));
+
+ // We may also update the length without adding real content. This is only
+ // written in the packet header.
+ packet.updateLength(128);
+ EXPECT_EQ(packet.payloadSize(),
+ std::size_t(original_payload_size + 200 + 128));
+}
+
+TEST_F(PacketTest, SetGetPayloadType) {
+ auto payload_type = packet.getPayloadType();
+
+ // It should be normal content object by default
+ EXPECT_EQ(payload_type, PayloadType::DATA);
+
+ // Set it to be manifest
+ packet.setPayloadType(PayloadType::MANIFEST);
+
+ // Check it is manifest
+ payload_type = packet.getPayloadType();
+
+ EXPECT_EQ(payload_type, PayloadType::MANIFEST);
+}
+
+TEST_F(PacketTest, GetFormat) {
+ {
+ PacketForTest p0(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET_TCP][0],
+ raw_packets_[Packet::Format::HF_INET_TCP].size(),
+ raw_packets_[Packet::Format::HF_INET_TCP].size());
+ testGetFormat(Packet::Format::HF_INET_TCP, p0);
+
+ PacketForTest p1(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET6_TCP][0],
+ raw_packets_[Packet::Format::HF_INET6_TCP].size(),
+ raw_packets_[Packet::Format::HF_INET6_TCP].size());
+ testGetFormat(Packet::Format::HF_INET6_TCP, p1);
+
+ PacketForTest p2(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET_ICMP][0],
+ raw_packets_[Packet::Format::HF_INET_ICMP].size(),
+ raw_packets_[Packet::Format::HF_INET_ICMP].size());
+ testGetFormat(Packet::Format::HF_INET_ICMP, p2);
+
+ PacketForTest p3(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET6_ICMP][0],
+ raw_packets_[Packet::Format::HF_INET6_ICMP].size(),
+ raw_packets_[Packet::Format::HF_INET6_ICMP].size());
+ testGetFormat(Packet::Format::HF_INET6_ICMP, p3);
+
+ PacketForTest p4(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET_TCP_AH][0],
+ raw_packets_[Packet::Format::HF_INET_TCP_AH].size(),
+ raw_packets_[Packet::Format::HF_INET_TCP_AH].size());
+ testGetFormat(Packet::Format::HF_INET_TCP_AH, p4);
+
+ PacketForTest p5(Packet::WRAP_BUFFER,
+ &raw_packets_[Packet::Format::HF_INET6_TCP_AH][0],
+ raw_packets_[Packet::Format::HF_INET6_TCP_AH].size(),
+ raw_packets_[Packet::Format::HF_INET6_TCP_AH].size());
+ testGetFormat(Packet::Format::HF_INET6_TCP_AH, p5);
+ }
+
+ // Let's try now creating empty packets
+ {
+ PacketForTest p0(Packet::Format::HF_INET_TCP);
+ testGetFormat(Packet::Format::HF_INET_TCP, p0);
+
+ PacketForTest p1(Packet::Format::HF_INET6_TCP);
+ testGetFormat(Packet::Format::HF_INET6_TCP, p1);
+
+ PacketForTest p2(Packet::Format::HF_INET_ICMP);
+ testGetFormat(Packet::Format::HF_INET_ICMP, p2);
+
+ PacketForTest p3(Packet::Format::HF_INET6_ICMP);
+ testGetFormat(Packet::Format::HF_INET6_ICMP, p3);
+
+ PacketForTest p4(Packet::Format::HF_INET_TCP_AH);
+ testGetFormat(Packet::Format::HF_INET_TCP_AH, p4);
+
+ PacketForTest p5(Packet::Format::HF_INET6_TCP_AH);
+ testGetFormat(Packet::Format::HF_INET6_TCP_AH, p5);
+ }
+}
+
+TEST_F(PacketTest, SetGetTestSignatureTimestamp) {
+ // Let's try to set the signature timestamp in a packet without AH header. We
+ // expect an exception.
+ using namespace std::chrono;
+ uint64_t now =
+ duration_cast<milliseconds>(system_clock::now().time_since_epoch())
+ .count();
+
+ try {
+ packet.setSignatureTimestamp(now);
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Same fot get method
+ try {
+ auto t = packet.getSignatureTimestamp();
+ // Let's make compiler happy
+ (void)t;
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Now let's construct a AH packet, with no additional space for signature
+ PacketForTest p(HF_INET6_TCP_AH);
+ p.setSignatureTimestamp(now);
+ uint64_t now_get = p.getSignatureTimestamp();
+
+ // Check we got the right value
+ EXPECT_EQ(now_get, now);
+}
+
+TEST_F(PacketTest, TestSetGetValidationAlgorithm) {
+ // Let's try to set the validation algorithm in a packet without AH header. We
+ // expect an exception.
+
+ try {
+ packet.setValidationAlgorithm(auth::CryptoSuite::RSA_SHA256);
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Same fot get method
+ try {
+ auto v = packet.getSignatureTimestamp();
+ // Let's make compiler happy
+ (void)v;
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Now let's construct a AH packet, with no additional space for signature
+ PacketForTest p(HF_INET6_TCP_AH);
+ p.setValidationAlgorithm(auth::CryptoSuite::RSA_SHA256);
+ auto v_get = p.getValidationAlgorithm();
+
+ // Check we got the right value
+ EXPECT_EQ(v_get, auth::CryptoSuite::RSA_SHA256);
+}
+
+TEST_F(PacketTest, TestSetGetKeyId) {
+ uint8_t key[32];
+ auth::KeyId key_id = std::make_pair(key, sizeof(key));
+
+ try {
+ packet.setKeyId(key_id);
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Same fot get method
+ try {
+ auto k = packet.getKeyId();
+ // Let's make compiler happy
+ (void)k;
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ // Now let's construct a AH packet, with no additional space for signature
+ PacketForTest p(HF_INET6_TCP_AH);
+ p.setKeyId(key_id);
+ auto p_get = p.getKeyId();
+
+ // Check we got the right value
+ EXPECT_EQ(p_get.second, key_id.second);
+
+ auto ret = memcmp(p_get.first, key_id.first, p_get.second);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST_F(PacketTest, DISABLED_TestChecksum) {
+ // Checksum should be wrong
+ bool integrity = packet.checkIntegrity();
+ EXPECT_FALSE(integrity);
+
+ // Let's fix it
+ packet.setChecksum();
+
+ // Check again
+ integrity = packet.checkIntegrity();
+ EXPECT_TRUE(integrity);
+
+ // Check with AH header and 300 bytes signature
+ PacketForTest p(HF_INET6_TCP_AH, 300);
+ std::string payload(5000, 'X');
+ p.appendPayload((const uint8_t *)payload.c_str(), payload.size() / 2);
+ p.appendPayload((const uint8_t *)(payload.c_str() + payload.size() / 2),
+ payload.size() / 2);
+
+ p.setChecksum();
+ integrity = p.checkIntegrity();
+ EXPECT_TRUE(integrity);
+}
+
+TEST_F(PacketTest, TestSetSyn) {
+ // Test syn of non-tcp format and check exception is thrown
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setSyn();
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setSyn();
+ EXPECT_TRUE(packet.testSyn());
+
+ packet.resetSyn();
+ EXPECT_FALSE(packet.testSyn());
+}
+
+TEST_F(PacketTest, TestSetFin) {
+ // Test syn of non-tcp format and check exception is thrown
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setFin();
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setFin();
+ EXPECT_TRUE(packet.testFin());
+
+ packet.resetFin();
+ EXPECT_FALSE(packet.testFin());
+}
+
+TEST_F(PacketTest, TestSetAck) {
+ // Test syn of non-tcp format and check exception is thrown
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setAck();
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setAck();
+ EXPECT_TRUE(packet.testAck());
+
+ packet.resetAck();
+ EXPECT_FALSE(packet.testAck());
+}
+
+TEST_F(PacketTest, TestSetRst) {
+ // Test syn of non-tcp format and check exception is thrown
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setRst();
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setRst();
+ EXPECT_TRUE(packet.testRst());
+
+ packet.resetRst();
+ EXPECT_FALSE(packet.testRst());
+}
+
+TEST_F(PacketTest, TestResetFlags) {
+ packet.setRst();
+ packet.setSyn();
+ packet.setAck();
+ packet.setFin();
+ EXPECT_TRUE(packet.testRst());
+ EXPECT_TRUE(packet.testAck());
+ EXPECT_TRUE(packet.testFin());
+ EXPECT_TRUE(packet.testSyn());
+
+ packet.resetFlags();
+ EXPECT_FALSE(packet.testRst());
+ EXPECT_FALSE(packet.testAck());
+ EXPECT_FALSE(packet.testFin());
+ EXPECT_FALSE(packet.testSyn());
+}
+
+TEST_F(PacketTest, TestSetGetSrcPort) {
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setSrcPort(12345);
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setSrcPort(12345);
+ EXPECT_EQ(packet.getSrcPort(), 12345);
+}
+
+TEST_F(PacketTest, TestSetGetDstPort) {
+ try {
+ auto p = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+ // Let's make compiler happy
+ p.setDstPort(12345);
+ FAIL() << "We should not reach this point.";
+ } catch (const errors::RuntimeException &exc) {
+ /* ok right exception*/
+ } catch (...) {
+ FAIL() << "Unexpected exception";
+ }
+
+ packet.setDstPort(12345);
+ EXPECT_EQ(packet.getDstPort(), 12345);
+}
+
+TEST_F(PacketTest, TestEnsureCapacity) {
+ PacketForTest &p = packet;
+
+ // This shoul be false
+ auto ret = p.ensureCapacity(raw_packets_[HF_INET6_TCP].size() + 10);
+ EXPECT_FALSE(ret);
+
+ // This should be true
+ ret = p.ensureCapacity(raw_packets_[HF_INET6_TCP].size());
+ EXPECT_TRUE(ret);
+
+ // This should be true
+ ret = p.ensureCapacity(raw_packets_[HF_INET6_TCP].size() - 10);
+ EXPECT_TRUE(ret);
+
+ // Try to trim the packet start
+ p.trimStart(10);
+ // Now this should be false
+ ret = p.ensureCapacity(raw_packets_[HF_INET6_TCP].size());
+ EXPECT_FALSE(ret);
+
+ // Create a new packet
+ auto p2 = PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_ICMP][0],
+ raw_packets_[HF_INET6_ICMP].size(),
+ raw_packets_[HF_INET6_ICMP].size());
+
+ p2.appendPayload(utils::MemBuf::createCombined(2000));
+
+ // This should be false, since the buffer is chained
+ ret = p2.ensureCapacity(raw_packets_[HF_INET6_TCP].size() - 10);
+ EXPECT_FALSE(ret);
+}
+
+TEST_F(PacketTest, TestEnsureCapacityAndFillUnused) {
+ // Create packet by excluding the payload (So only L3 + L4 headers). The
+ // payload will be trated as unused tailroom
+ PacketForTest p =
+ PacketForTest(Packet::WRAP_BUFFER, &raw_packets_[HF_INET6_TCP][0],
+ raw_packets_[HF_INET6_TCP].size() - PAYLOAD_SIZE,
+ raw_packets_[HF_INET6_TCP].size());
+
+ // Copy original packet payload, which is here trated as a unused tailroom
+ uint8_t original_payload[PAYLOAD_SIZE];
+ uint8_t *payload = &raw_packets_[HF_INET6_TCP][0] +
+ raw_packets_[HF_INET6_TCP].size() - PAYLOAD_SIZE;
+ std::memcpy(original_payload, payload, PAYLOAD_SIZE);
+
+ // This should be true and the unused tailroom should be unmodified
+ auto ret = p.ensureCapacityAndFillUnused(
+ raw_packets_[HF_INET6_TCP].size() - (PAYLOAD_SIZE + 10), 0);
+ EXPECT_TRUE(ret);
+ ret = std::memcmp(original_payload, payload, PAYLOAD_SIZE);
+ EXPECT_EQ(ret, 0);
+
+ // This should fill the payload with zeros
+ ret = p.ensureCapacityAndFillUnused(raw_packets_[HF_INET6_TCP].size(), 0);
+ EXPECT_TRUE(ret);
+ uint8_t zeros[PAYLOAD_SIZE];
+ std::memset(zeros, 0, PAYLOAD_SIZE);
+ ret = std::memcmp(payload, zeros, PAYLOAD_SIZE);
+ EXPECT_EQ(ret, 0);
+
+ // This should fill the payload with ones
+ ret = p.ensureCapacityAndFillUnused(raw_packets_[HF_INET6_TCP].size(), 1);
+ EXPECT_TRUE(ret);
+ uint8_t ones[PAYLOAD_SIZE];
+ std::memset(ones, 1, PAYLOAD_SIZE);
+ ret = std::memcmp(payload, ones, PAYLOAD_SIZE);
+ EXPECT_EQ(ret, 0);
+
+ // This should return false and the payload should be unmodified
+ ret = p.ensureCapacityAndFillUnused(raw_packets_[HF_INET6_TCP].size() + 1, 1);
+ EXPECT_FALSE(ret);
+ ret = std::memcmp(payload, ones, PAYLOAD_SIZE);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST_F(PacketTest, TestSetGetTTL) {
+ packet.setTTL(128);
+ EXPECT_EQ(packet.getTTL(), 128);
+}
+
+} // namespace core
+} // namespace transport
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}