aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/test
diff options
context:
space:
mode:
authorLuca Muscariello <muscariello@ieee.org>2021-04-15 09:05:46 +0200
committerMauro Sardara <msardara@cisco.com>2021-04-15 16:36:16 +0200
commite92e9e839ca2cf42b56322b2489ccc0d8bf767af (patch)
tree9f1647c83a87fbf982ae329e800af25dbfb226b5 /libtransport/src/test
parent3e541d7c947cc2f9db145f26c9274efd29a6fb56 (diff)
[HICN-690] Transport Library Major Refactory
The current patch provides a major refactory of the transportlibrary. A summary of the different components that underwent major modifications is reported below. - Transport protocol updates The hierarchy of classes has been optimized to have common transport services across different transport protocols. This can allow to customize a transport protocol with new features. - A new real-time communication protocol The RTC protocol has been optimized in terms of algorithms to reduce consumer-producer synchronization latency. - A novel socket API The API has been reworked to be easier to consumer but also to have a more efficient integration in L4 proxies. - Several performance improvements A large number of performance improvements have been included in particular to make the entire stack zero-copy and optimize cache miss. - New memory buffer framework Memory management has been reworked entirely to provide a more efficient infra with a richer API. Buffers are now allocated in blocks and a single buffer holds the memory for (1) the shared_ptr control block, (2) the metadata of the packet (e.g. name, pointer to other buffers if buffer is chained and relevant offsets), and (3) the packet itself, as it is sent/received over the network. - A new slab allocator Dynamic memory allocation is now managed by a novel slab allocator that is optimised for packet processing and connection management. Memory is organized in pools of blocks all of the same size which are used during the processing of outgoing/incoming packets. When a memory block Is allocated is always taken from a global pool and when it is deallocated is returned to the pool, thus avoiding the cost of any heap allocation in the data path. - New transport connectors Consumer and producer end-points can communication either using an hicn packet forwarder or with direct connector based on shared memories or sockets. The usage of transport connectors typically for unit and funcitonal testing but may have additional usage. - Support for FEC/ECC for transport services FEC/ECC via reed solomon is supported by default and made available to transport services as a modular component. Reed solomon block codes is a default FEC model that can be replaced in a modular way by many other codes including RLNC not avaiable in this distribution. The current FEC framework support variable size padding and efficiently makes use of the infra memory buffers to avoid additiona copies. - Secure transport framework for signature computation and verification Crypto support is nativelty used in hICN for integrity and authenticity. Novel support that includes RTC has been implemented and made modular and reusable acrosso different transport protocols. - TLS - Transport layer security over hicn Point to point confidentiality is provided by integrating TLS on top of hICN reliable and non-reliable transport. The integration is common and makes a different use of the TLS record. - MLS - Messaging layer security over hicn MLS integration on top of hICN is made by using the MLSPP implemetation open sourced by Cisco. We have included instrumentation tools to deploy performance and functional tests of groups of end-points. - Android support The overall code has been heavily tested in Android environments and has received heavy lifting to better run natively in recent Android OS. Co-authored-by: Mauro Sardara <msardara@cisco.com> Co-authored-by: Michele Papalini <micpapal@cisco.com> Co-authored-by: Olivier Roques <oroques+fdio@cisco.com> Co-authored-by: Giulio Grassi <gigrassi@cisco.com> Change-Id: If477ba2fa686e6f47bdf96307ac60938766aef69 Signed-off-by: Luca Muscariello <muscariello@ieee.org>
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();
+}