From f4433f28b509a9f67ca85d79000ccf9c2f4b7a24 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 21 Feb 2020 11:52:28 +0100 Subject: [HICN-534] Major rework on libtransport organization Change-Id: I361b83a18b4fd59be136d5f0817fc28e17e89884 Signed-off-by: Mauro Sardara --- .../includes/hicn/transport/CMakeLists.txt | 38 + .../includes/hicn/transport/core/CMakeLists.txt | 25 + .../includes/hicn/transport/core/content_object.h | 77 ++ .../includes/hicn/transport/core/interest.h | 71 ++ libtransport/includes/hicn/transport/core/name.h | 142 +++ libtransport/includes/hicn/transport/core/packet.h | 203 ++++ .../includes/hicn/transport/core/payload_type.h | 29 + libtransport/includes/hicn/transport/core/prefix.h | 80 ++ .../includes/hicn/transport/errors/CMakeLists.txt | 30 + .../includes/hicn/transport/errors/errors.h | 24 + .../hicn/transport/errors/indexing_exception.h | 31 + .../errors/invalid_ip_address_exception.h | 31 + .../errors/malformed_ahpacket_exception.h | 31 + .../transport/errors/malformed_name_exception.h | 31 + .../transport/errors/malformed_packet_exception.h | 29 + .../transport/errors/not_implemented_exception.h | 30 + .../hicn/transport/errors/null_pointer_exception.h | 31 + .../hicn/transport/errors/runtime_exception.h | 32 + .../hicn/transport/errors/tokenizer_exception.h | 31 + .../errors/unexpected_manifest_exception.h | 31 + .../includes/hicn/transport/http/CMakeLists.txt | 25 + .../hicn/transport/http/client_connection.h | 80 ++ .../includes/hicn/transport/http/default_values.h | 32 + libtransport/includes/hicn/transport/http/facade.h | 20 + .../includes/hicn/transport/http/message.h | 70 ++ .../includes/hicn/transport/http/request.h | 56 ++ .../includes/hicn/transport/http/response.h | 58 ++ .../hicn/transport/interfaces/CMakeLists.txt | 35 + .../includes/hicn/transport/interfaces/callbacks.h | 116 +++ .../interfaces/p2psecure_socket_consumer.h | 32 + .../interfaces/p2psecure_socket_producer.h | 36 + .../transport/interfaces/publication_options.h | 43 + .../transport/interfaces/rtc_socket_producer.h | 32 + .../hicn/transport/interfaces/socket_consumer.h | 298 ++++++ .../interfaces/socket_options_default_values.h | 69 ++ .../transport/interfaces/socket_options_keys.h | 118 +++ .../hicn/transport/interfaces/socket_producer.h | 149 +++ .../hicn/transport/interfaces/statistics.h | 121 +++ .../transport/interfaces/verification_policy.h | 33 + .../hicn/transport/portability/CMakeLists.txt | 31 + .../hicn/transport/portability/c_portability.h | 36 + .../hicn/transport/portability/portability.h | 50 + .../hicn/transport/portability/win_portability.h | 42 + .../hicn/transport/security/CMakeLists.txt | 27 + .../includes/hicn/transport/security/crypto_hash.h | 119 +++ .../hicn/transport/security/crypto_hash_type.h | 31 + .../hicn/transport/security/crypto_hasher.h | 68 ++ .../hicn/transport/security/crypto_suite.h | 36 + .../includes/hicn/transport/security/identity.h | 63 ++ .../includes/hicn/transport/security/key_id.h | 25 + .../includes/hicn/transport/security/signer.h | 90 ++ .../includes/hicn/transport/security/verifier.h | 103 ++ .../includes/hicn/transport/utils/CMakeLists.txt | 39 + libtransport/includes/hicn/transport/utils/array.h | 62 ++ .../hicn/transport/utils/branch_prediction.h | 27 + .../hicn/transport/utils/chrono_typedefs.h | 27 + .../includes/hicn/transport/utils/conversions.h | 37 + .../includes/hicn/transport/utils/daemonizator.h | 30 + libtransport/includes/hicn/transport/utils/hash.h | 101 ++ libtransport/includes/hicn/transport/utils/linux.h | 64 ++ .../includes/hicn/transport/utils/literals.h | 55 + libtransport/includes/hicn/transport/utils/log.h | 1057 ++++++++++++++++++++ .../includes/hicn/transport/utils/membuf.h | 921 +++++++++++++++++ .../includes/hicn/transport/utils/object_pool.h | 90 ++ .../includes/hicn/transport/utils/ring_buffer.h | 129 +++ .../includes/hicn/transport/utils/spinlock.h | 53 + .../hicn/transport/utils/string_tokenizer.h | 35 + libtransport/includes/hicn/transport/utils/uri.h | 47 + 68 files changed, 5945 insertions(+) create mode 100644 libtransport/includes/hicn/transport/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/core/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/core/content_object.h create mode 100644 libtransport/includes/hicn/transport/core/interest.h create mode 100644 libtransport/includes/hicn/transport/core/name.h create mode 100644 libtransport/includes/hicn/transport/core/packet.h create mode 100644 libtransport/includes/hicn/transport/core/payload_type.h create mode 100644 libtransport/includes/hicn/transport/core/prefix.h create mode 100644 libtransport/includes/hicn/transport/errors/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/errors/errors.h create mode 100644 libtransport/includes/hicn/transport/errors/indexing_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_name_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/malformed_packet_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/not_implemented_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/null_pointer_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/runtime_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/tokenizer_exception.h create mode 100644 libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h create mode 100644 libtransport/includes/hicn/transport/http/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/http/client_connection.h create mode 100644 libtransport/includes/hicn/transport/http/default_values.h create mode 100644 libtransport/includes/hicn/transport/http/facade.h create mode 100644 libtransport/includes/hicn/transport/http/message.h create mode 100644 libtransport/includes/hicn/transport/http/request.h create mode 100644 libtransport/includes/hicn/transport/http/response.h create mode 100644 libtransport/includes/hicn/transport/interfaces/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/interfaces/callbacks.h create mode 100644 libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/publication_options.h create mode 100644 libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_consumer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_options_keys.h create mode 100644 libtransport/includes/hicn/transport/interfaces/socket_producer.h create mode 100644 libtransport/includes/hicn/transport/interfaces/statistics.h create mode 100644 libtransport/includes/hicn/transport/interfaces/verification_policy.h create mode 100644 libtransport/includes/hicn/transport/portability/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/portability/c_portability.h create mode 100644 libtransport/includes/hicn/transport/portability/portability.h create mode 100644 libtransport/includes/hicn/transport/portability/win_portability.h create mode 100644 libtransport/includes/hicn/transport/security/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/security/crypto_hash.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_hash_type.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_hasher.h create mode 100644 libtransport/includes/hicn/transport/security/crypto_suite.h create mode 100644 libtransport/includes/hicn/transport/security/identity.h create mode 100644 libtransport/includes/hicn/transport/security/key_id.h create mode 100644 libtransport/includes/hicn/transport/security/signer.h create mode 100644 libtransport/includes/hicn/transport/security/verifier.h create mode 100644 libtransport/includes/hicn/transport/utils/CMakeLists.txt create mode 100644 libtransport/includes/hicn/transport/utils/array.h create mode 100644 libtransport/includes/hicn/transport/utils/branch_prediction.h create mode 100644 libtransport/includes/hicn/transport/utils/chrono_typedefs.h create mode 100644 libtransport/includes/hicn/transport/utils/conversions.h create mode 100644 libtransport/includes/hicn/transport/utils/daemonizator.h create mode 100644 libtransport/includes/hicn/transport/utils/hash.h create mode 100644 libtransport/includes/hicn/transport/utils/linux.h create mode 100644 libtransport/includes/hicn/transport/utils/literals.h create mode 100644 libtransport/includes/hicn/transport/utils/log.h create mode 100644 libtransport/includes/hicn/transport/utils/membuf.h create mode 100644 libtransport/includes/hicn/transport/utils/object_pool.h create mode 100644 libtransport/includes/hicn/transport/utils/ring_buffer.h create mode 100644 libtransport/includes/hicn/transport/utils/spinlock.h create mode 100644 libtransport/includes/hicn/transport/utils/string_tokenizer.h create mode 100644 libtransport/includes/hicn/transport/utils/uri.h (limited to 'libtransport/includes') diff --git a/libtransport/includes/hicn/transport/CMakeLists.txt b/libtransport/includes/hicn/transport/CMakeLists.txt new file mode 100644 index 000000000..1099e701d --- /dev/null +++ b/libtransport/includes/hicn/transport/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2017-2020 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +include(GNUInstallDirs) + +set(ASIO_STANDALONE 1) + +add_subdirectory(core) +add_subdirectory(errors) +add_subdirectory(http) +add_subdirectory(interfaces) +add_subdirectory(portability) +add_subdirectory(security) +add_subdirectory(utils) + +set(LIBTRANSPORT_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/../.. "" + CACHE INTERNAL + "" FORCE +) + +set(LIBHICNTRANSPORT_TO_INSTALL_HEADER_FILES + ${HEADER_FILES} "" + CACHE INTERNAL + "" FORCE +) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/CMakeLists.txt b/libtransport/includes/hicn/transport/core/CMakeLists.txt new file mode 100644 index 000000000..cb10745ff --- /dev/null +++ b/libtransport/includes/hicn/transport/core/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h + ${CMAKE_CURRENT_SOURCE_DIR}/interest.h + ${CMAKE_CURRENT_SOURCE_DIR}/name.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet.h + ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/content_object.h b/libtransport/includes/hicn/transport/core/content_object.h new file mode 100644 index 000000000..5af548fe4 --- /dev/null +++ b/libtransport/includes/hicn/transport/core/content_object.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +// This class is used just to transfer buffer pointers +// without making a copy, as std::vector<> would do + +class ContentObject : public Packet { + public: + using Ptr = utils::ObjectPool::Ptr; + using HICNContentObject = hicn_header_t; + + ContentObject(Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload, + std::size_t payload_size); + + ContentObject(const uint8_t *buffer, std::size_t size); + ContentObject(MemBufPtr &&buffer); + + ContentObject(const ContentObject &content_object) = delete; + + ContentObject(ContentObject &&content_object); + + ~ContentObject() override; + + void replace(MemBufPtr &&buffer) override; + + const Name &getName() const override; + + Name &getWritableName() override; + + void setName(const Name &name) override; + + void setName(Name &&name) override; + + uint32_t getPathLabel() const; + + ContentObject &setPathLabel(uint32_t path_label); + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + void setLifetime(uint32_t lifetime) override; + + uint32_t getLifetime() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/interest.h b/libtransport/includes/hicn/transport/core/interest.h new file mode 100644 index 000000000..f0c546a8e --- /dev/null +++ b/libtransport/includes/hicn/transport/core/interest.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +class Interest + : public Packet /*, public std::enable_shared_from_this*/ { + public: + using Ptr = utils::ObjectPool::Ptr; + + Interest(Packet::Format format = HF_INET6_TCP); + + Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP); + + Interest(const uint8_t *buffer, std::size_t size); + Interest(MemBufPtr &&buffer); + + /* + * Enforce zero-copy. + */ + Interest(const Interest &other_interest) = delete; + Interest &operator=(const Interest &other_interest) = delete; + + Interest(Interest &&other_interest); + + ~Interest() override; + + void replace(MemBufPtr &&buffer) override; + + const Name &getName() const override; + + Name &getWritableName() override; + + void setName(const Name &name) override; + + void setName(Name &&name) override; + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + void setLifetime(uint32_t lifetime) override; + + uint32_t getLifetime() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/name.h b/libtransport/includes/hicn/transport/core/name.h new file mode 100644 index 000000000..ea72797ad --- /dev/null +++ b/libtransport/includes/hicn/transport/core/name.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +extern "C" { +#ifndef _WIN32 +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#endif +#include +}; + +#include + +namespace transport { + +namespace core { + +typedef struct sockaddr_in6 Sockaddr6; +typedef struct sockaddr_in Sockaddr4; +typedef struct sockaddr Sockaddr; + +enum class HashAlgorithm : uint8_t; + +class Name { + friend class Packet; + friend class ContentObject; + friend class Interest; + + static const uint32_t standard_name_string_length = 100; + + public: + using NameStruct = hicn_name_t; + using Type = hicn_name_type_t; + + Name(); + + /** + * @brief Create name + * @param name The null-terminated URI string + */ + Name(const char *name, uint32_t segment); + + Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0); + + Name(const std::string &uri, uint32_t segment); + + Name(const std::string &uri); + + Name(const Name &name); + + Name &operator=(const Name &name); + + bool operator==(const Name &name) const; + + bool operator!=(const Name &name) const; + + operator bool() const; + + std::string toString() const; + + bool equals(const Name &name, bool consider_segment = true) const; + + uint32_t getHash32(bool consider_suffix = true) const; + + void clear(); + + Type getType() const; + + uint32_t getSuffix() const; + + std::shared_ptr getAddress() const; + + Name &setSuffix(uint32_t seq_number); + + ip_prefix_t toIpAddress() const; + + void copyToDestination(uint8_t *destination, + bool include_suffix = false) const; + + int getAddressFamily() const; + + private: + TRANSPORT_ALWAYS_INLINE const NameStruct *getConstStructReference() const { + return &name_; + } + + TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() { return &name_; } + + NameStruct name_; +}; + +std::ostream &operator<<(std::ostream &os, const Name &name); + +template +struct hash {}; + +template <> +struct hash { + size_t operator()(const transport::core::Name &name) const; +}; + +template +struct compare2 {}; + +template <> +struct compare2 { + size_t operator()(const transport::core::Name &name1, const transport::core::Name &name2) const; +}; + +} // end namespace core + +} // end namespace transport + + +namespace std { +template <> +struct hash { + size_t operator()(const transport::core::Name &name) const; +}; + +} // end namespace std diff --git a/libtransport/includes/hicn/transport/core/packet.h b/libtransport/includes/hicn/transport/core/packet.h new file mode 100644 index 000000000..e80912cbe --- /dev/null +++ b/libtransport/includes/hicn/transport/core/packet.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace utils { +class Signer; +class Verifier; +} // namespace utils + +namespace transport { + +namespace core { + +/* + * Basic IP packet, modelled as circular chain of buffers: + * Header = H + * Payload = P + * + * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2 + * \_______________________________________| + */ + +class Packet : public std::enable_shared_from_this { + friend class utils::Signer; + friend class utils::Verifier; + + public: + using MemBufPtr = std::shared_ptr; + using Format = hicn_format_t; + static constexpr size_t default_mtu = 1500; + + /** + * Create new IP packet. Here we allocate just the header, + * the eventual payload will be added by prepending the payload buffer + * to the buffer chain whose the fist buffer is the header itself. + */ + Packet(Format format = HF_UNSPEC); + + /** + * Create new IP packet using raw buffer. + */ + Packet(const uint8_t *buffer, std::size_t size); + Packet(MemBufPtr &&buffer); + + /* + * Enforce zero-copy lifestyle. + */ + Packet(const Packet &other) = delete; + Packet &operator=(const Packet &other) = delete; + + /* + * Move constructor. + */ + Packet(Packet &&other); + + friend bool operator==(const Packet &l_packet, const Packet &r_packet); + + virtual ~Packet(); + + static std::size_t getHeaderSizeFromFormat(Format format, + std::size_t signature_size = 0); + + static std::size_t getHeaderSizeFromBuffer(Format format, + const uint8_t *buffer); + + static std::size_t getPayloadSizeFromBuffer(Format format, + const uint8_t *buffer); + + static bool isInterest(const uint8_t *buffer); + + static Format getFormatFromBuffer(const uint8_t *buffer); + + virtual void replace(MemBufPtr &&buffer); + + std::size_t payloadSize() const; + + std::size_t headerSize() const; + + const std::shared_ptr acquireMemBufReference() const; + + virtual const Name &getName() const = 0; + + virtual Name &getWritableName() = 0; + + virtual void setName(const Name &name) = 0; + + virtual void setName(Name &&name) = 0; + + virtual void setLifetime(uint32_t lifetime) = 0; + + virtual uint32_t getLifetime() const = 0; + + Packet &appendPayload(const uint8_t *buffer, std::size_t length); + + Packet &appendPayload(std::unique_ptr &&payload); + + Packet &appendHeader(std::unique_ptr &&header); + + Packet &appendHeader(const uint8_t *buffer, std::size_t length); + + std::unique_ptr getPayload() const; + + Packet &updateLength(std::size_t length = 0); + + PayloadType getPayloadType() const; + + Packet &setPayloadType(PayloadType payload_type); + + Format getFormat() const; + + void dump() const; + + virtual void setLocator(const ip_address_t &locator) = 0; + + virtual ip_address_t getLocator() const = 0; + + void setSignatureTimestamp(const uint64_t ×tamp); + + uint64_t getSignatureTimestamp() const; + + void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm); + + utils::CryptoSuite getValidationAlgorithm() const; + + void setKeyId(const utils::KeyId &key_id); + + utils::KeyId getKeyId() const; + + virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const; + + void setChecksum(); + + bool checkIntegrity() const; + + Packet &setSyn(); + Packet &resetSyn(); + bool testSyn() const; + Packet &setAck(); + Packet &resetAck(); + bool testAck() const; + Packet &setRst(); + Packet &resetRst(); + bool testRst() const; + Packet &setFin(); + Packet &resetFin(); + bool testFin() const; + Packet &resetFlags(); + std::string printFlags() const; + + Packet &setSrcPort(uint16_t srcPort); + Packet &setDstPort(uint16_t dstPort); + uint16_t getSrcPort() const; + uint16_t getDstPort() const; + + Packet &setTTL(uint8_t hops); + uint8_t getTTL() const; + + void resetPayload(); + + private: + virtual void resetForHash() = 0; + void setSignatureSize(std::size_t size_bytes); + std::size_t getSignatureSize() const; + uint8_t *getSignature() const; + void separateHeaderPayload(); + + protected: + Name name_; + MemBufPtr packet_; + hicn_header_t *packet_start_; + utils::MemBuf *header_head_; + utils::MemBuf *payload_head_; + mutable Format format_; + + static const core::Name base_name; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/core/payload_type.h b/libtransport/includes/hicn/transport/core/payload_type.h new file mode 100644 index 000000000..fa79db35a --- /dev/null +++ b/libtransport/includes/hicn/transport/core/payload_type.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace transport { + +namespace core { + +enum class PayloadType : uint16_t { + CONTENT_OBJECT = HPT_DATA, + MANIFEST = HPT_MANIFEST, +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/core/prefix.h b/libtransport/includes/hicn/transport/core/prefix.h new file mode 100644 index 000000000..c3805f13f --- /dev/null +++ b/libtransport/includes/hicn/transport/core/prefix.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { + +namespace core { + +class Prefix { + public: + Prefix(); + + Prefix(const char *prefix); + + Prefix(const std::string &prefix); + + Prefix(std::string &&prefix); + + Prefix(std::string &prefix, uint16_t prefix_length); + + Prefix(const core::Name &content_name, uint16_t prefix_length); + + std::unique_ptr toSockaddr(); + + uint16_t getPrefixLength(); + + Prefix &setPrefixLength(uint16_t prefix_length); + + std::string getNetwork() const; + + int contains(const ip_address_t &content_name) const; + + int contains(const core::Name &content_name) const; + + Name getName() const; + + Name getRandomName() const; + + Name getName(const core::Name &mask, const core::Name &components, + const core::Name &content_name) const; + + Name mapName(const core::Name &content_name) const; + + Prefix &setNetwork(std::string &network); + + int getAddressFamily(); + + Prefix &setAddressFamily(int address_family); + + Name makeRandomName() const; + + ip_prefix_t &toIpPrefixStruct(); + + private: + static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length, + int family); + + void buildPrefix(std::string &prefix, uint16_t prefix_length, int family); + + ip_prefix_t ip_prefix_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/errors/CMakeLists.txt b/libtransport/includes/hicn/transport/errors/CMakeLists.txt new file mode 100644 index 000000000..5b04ace10 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/not_implemented_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/invalid_ip_address_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_name_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/errors.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_packet_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/runtime_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/null_pointer_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/malformed_ahpacket_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/unexpected_manifest_exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/indexing_exception.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/errors.h b/libtransport/includes/hicn/transport/errors/errors.h new file mode 100644 index 000000000..512e35736 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/errors.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/indexing_exception.h b/libtransport/includes/hicn/transport/errors/indexing_exception.h new file mode 100644 index 000000000..731314f0e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/indexing_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class IndexingException : public std::logic_error { + public: + IndexingException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "Impossible to retrieve next index to download."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h new file mode 100644 index 000000000..60226f576 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/invalid_ip_address_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class InvalidIpAddressException : public std::runtime_error { + public: + InvalidIpAddressException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed IP address."; + } +}; + +} // end namespace errors \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h new file mode 100644 index 000000000..f0cfe0b82 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_ahpacket_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedAHPacketException : public std::runtime_error { + public: + MalformedAHPacketException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed AH packet."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/malformed_name_exception.h b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h new file mode 100644 index 000000000..4ef45d2e8 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_name_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedNameException : public std::runtime_error { + public: + MalformedNameException() : std::runtime_error("") {} + + virtual char const *what() const noexcept override { + return "Malformed IP address."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h new file mode 100644 index 000000000..ec5c97e6e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/malformed_packet_exception.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class MalformedPacketException : public std::runtime_error { + public: + MalformedPacketException() : std::runtime_error("") {} + + char const *what() const noexcept override { return "Malformed IP packet."; } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/not_implemented_exception.h b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h new file mode 100644 index 000000000..e9869163d --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/not_implemented_exception.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class NotImplementedException : public std::logic_error { + public: + NotImplementedException() : std::logic_error("") {} + virtual char const *what() const noexcept override { + return "Function not yet implemented."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/null_pointer_exception.h b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h new file mode 100644 index 000000000..bd06485ed --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/null_pointer_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class NullPointerException : public std::runtime_error { + public: + NullPointerException() : std::runtime_error("") {} + + char const *what() const noexcept override { + return "Null pointer exception."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/runtime_exception.h b/libtransport/includes/hicn/transport/errors/runtime_exception.h new file mode 100644 index 000000000..ba5128a7e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/runtime_exception.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace errors { + +class RuntimeException : public std::runtime_error { + public: + RuntimeException() : std::runtime_error("") {} + + RuntimeException(std::string what) : runtime_error(what){}; +}; + +} // end namespace errors \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/errors/tokenizer_exception.h b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h new file mode 100644 index 000000000..76eda838e --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/tokenizer_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class TokenizerException : public std::logic_error { + public: + TokenizerException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "No more tokens available."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h new file mode 100644 index 000000000..6f71471e4 --- /dev/null +++ b/libtransport/includes/hicn/transport/errors/unexpected_manifest_exception.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace errors { + +class UnexpectedManifestException : public std::logic_error { + public: + UnexpectedManifestException() : std::logic_error("") {} + + virtual char const *what() const noexcept override { + return "Received unexpected manifest."; + } +}; + +} // end namespace errors diff --git a/libtransport/includes/hicn/transport/http/CMakeLists.txt b/libtransport/includes/hicn/transport/http/CMakeLists.txt new file mode 100644 index 000000000..9cf618c21 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2017-2020 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.h + ${CMAKE_CURRENT_SOURCE_DIR}/request.h + ${CMAKE_CURRENT_SOURCE_DIR}/default_values.h + ${CMAKE_CURRENT_SOURCE_DIR}/facade.h + ${CMAKE_CURRENT_SOURCE_DIR}/response.h + ${CMAKE_CURRENT_SOURCE_DIR}/message.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/client_connection.h b/libtransport/includes/hicn/transport/http/client_connection.h new file mode 100644 index 000000000..262756a09 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/client_connection.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace http { + +using namespace interface; +using namespace core; + +class HTTPClientConnection { + static constexpr uint32_t max_buffer_capacity = 64 * 1024; + + public: + class ReadBytesCallback { + public: + virtual void onBytesReceived(std::unique_ptr &&buffer) = 0; + virtual void onSuccess(std::size_t bytes) = 0; + virtual void onError(const std::error_code ec) = 0; + }; + + enum class RC : uint32_t { DOWNLOAD_FAILED, DOWNLOAD_SUCCESS }; + + HTTPClientConnection(); + + ~HTTPClientConnection(); + + RC get(const std::string &url, HTTPHeaders headers = {}, + HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001"); + + RC sendRequest(const std::string &url, HTTPMethod method, + HTTPHeaders headers = {}, HTTPPayload &&payload = nullptr, + std::shared_ptr response = nullptr, + ReadBytesCallback *callback = nullptr, + std::string ipv6_first_word = "b001"); + + std::shared_ptr response(); + + HTTPClientConnection &stop(); + + interface::ConsumerSocket &getConsumer(); + + HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout); + + HTTPClientConnection &setCertificate(const std::string &cert_path); + + private: + class Implementation; + Implementation *implementation_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/default_values.h b/libtransport/includes/hicn/transport/http/default_values.h new file mode 100644 index 000000000..2d5a6b821 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/default_values.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { + +namespace http { + +namespace default_values { + +const uint16_t ipv6_first_word = 0xb001; // Network byte order + +} // namespace default_values + +} // namespace http + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/http/facade.h b/libtransport/includes/hicn/transport/http/facade.h new file mode 100644 index 000000000..8a465ce94 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/facade.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace libl4 = transport; \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/message.h b/libtransport/includes/hicn/transport/http/message.h new file mode 100644 index 000000000..b8756224f --- /dev/null +++ b/libtransport/includes/hicn/transport/http/message.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef _WIN32 +#include +#endif + +#include + +#include +#include +#include + +#define HTTP_VERSION "1.1" + +namespace transport { + +namespace http { + +typedef enum { GET, POST, PUT, PATCH, DELETE } HTTPMethod; + +static std::map method_map = { + {GET, "GET"}, {POST, "POST"}, {PUT, "PUT"}, + {PATCH, "PATCH"}, {DELETE, "DELETE"}, +}; + +typedef std::map HTTPHeaders; +typedef std::unique_ptr HTTPPayload; + +class HTTPMessage { + public: + virtual ~HTTPMessage() = default; + + const HTTPHeaders getHeaders() { return headers_; }; + + void coalescePayloadBuffer() { + auto it = headers_.find("Content-Length"); + if (it != headers_.end()) { + auto content_length = std::stoul(it->second); + payload_->gather(content_length); + } + } + + HTTPPayload &&getPayload() { return std::move(payload_); } + + std::string getHttpVersion() const { return http_version_; }; + + protected: + HTTPHeaders headers_; + HTTPPayload payload_; + std::string http_version_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/request.h b/libtransport/includes/hicn/transport/http/request.h new file mode 100644 index 000000000..54904d696 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/request.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace transport { + +namespace http { + +class HTTPRequest : public HTTPMessage { + public: + HTTPRequest(); + HTTPRequest(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload); + + void init(HTTPMethod method, const std::string &url, + const HTTPHeaders &headers, HTTPPayload &&payload); + + std::string getQueryString() const; + + std::string getPath() const; + + std::string getProtocol() const; + + std::string getLocator() const; + + std::string getPort() const; + + std::string getRequestString() const; + + private: + std::string query_string_, path_, protocol_, locator_, port_; + std::string request_string_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/http/response.h b/libtransport/includes/hicn/transport/http/response.h new file mode 100644 index 000000000..bab41acb8 --- /dev/null +++ b/libtransport/includes/hicn/transport/http/response.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace transport { + +namespace http { + +class HTTPResponse : public HTTPMessage { + public: + HTTPResponse(); + + HTTPResponse(std::unique_ptr &&response); + + void appendResponseChunk(std::unique_ptr &&response_chunk); + + const std::string &getStatusCode() const; + + const std::string &getStatusString() const; + + void parse(std::unique_ptr &&response); + + bool parseHeaders(std::unique_ptr &&buffer); + + static std::size_t parseHeaders(const uint8_t *buffer, std::size_t size, + HTTPHeaders &headers, + std::string &http_version, + std::string &status_code, + std::string &status_string); + + private: + std::string status_code_; + std::string status_string_; +}; + +} // end namespace http + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt new file mode 100644 index 000000000..38e6143f0 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/publication_options.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_default_values.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_keys.h + ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.h + ${CMAKE_CURRENT_SOURCE_DIR}/verification_policy.h + ${CMAKE_CURRENT_SOURCE_DIR}/statistics.h +) + +if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h + ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/includes/hicn/transport/interfaces/callbacks.h b/libtransport/includes/hicn/transport/interfaces/callbacks.h new file mode 100644 index 000000000..6ae07797e --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/callbacks.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace utils { +class MemBuf; +} + +namespace transport { + +namespace protocol { + +class IcnObserver; + +} // namespace protocol + +namespace core { +class ContentObject; +class Interest; +} // namespace core + +namespace interface { + +// Forward declarations +class ConsumerSocket; +class ProducerSocket; + +/** + * The ConsumerInterestCallback will be called in different parts of the + * consumer socket processing pipeline, with a ConsumerSocket and an Interest as + * parameters. + */ +using ConsumerInterestCallback = + std::function; + +/** + * The ConsumerTimerCallback is called periodically for exposing to applications + * a summary of the statistics of the transport protocol in use. + */ +using ConsumerTimerCallback = + std::function; + +/** + * The ProducerContentCallback will be called by the producer socket right after + * a content has been segmented and published. + */ +using ProducerContentCallback = std::function; + +/** + * The ConsumerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ConsumerSocket and an + * ContentObject as parameters. + */ +using ConsumerContentObjectCallback = + std::function; + +/** + * The ConsumerContentObjectVerificationCallback will be called by the transport + * if an application is willing to verify each content object. Note that a + * better alternative is to instrument the transport to perform the verification + * autonomously, without requiring the intervention of the application. + */ +using ConsumerContentObjectVerificationCallback = + std::function; + +/** + * The ConsumerContentObjectVerificationFailedCallback will be caled by the + * transport if a data packet (either manifest or content object) cannot be + * verified. The application here decides what to do by returning a + * VerificationFailedPolicy object. + */ +using ConsumerContentObjectVerificationFailedCallback = + std::function; + +/** + * The ProducerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ProducerSocket and an + * ContentObject as parameters. + */ +using ProducerContentObjectCallback = + std::function; + +/** + * The ProducerContentObjectCallback will be called in different parts of the + * consumer socket processing pipeline, with a ProducerSocket and an + * Interest as parameters. + */ +using ProducerInterestCallback = + std::function; + +extern std::nullptr_t VOID_HANDLER; + +} // namespace interface + +} // namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h new file mode 100644 index 000000000..097b0a8c0 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { + +namespace interface { + +class P2PSecureConsumerSocket : public ConsumerSocket { + public: + P2PSecureConsumerSocket(int handshake_protocol, int protocol); + ~P2PSecureConsumerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h new file mode 100644 index 000000000..6f0d48bb9 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace transport { + +namespace interface { + +class P2PSecureProducerSocket : public ProducerSocket { + public: + P2PSecureProducerSocket(); + P2PSecureProducerSocket(bool rtc, + const std::shared_ptr &identity); + ~P2PSecureProducerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/publication_options.h b/libtransport/includes/hicn/transport/interfaces/publication_options.h new file mode 100644 index 000000000..6910e5371 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/publication_options.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { + +namespace interface { + +class PublicationOptions { + public: + template + PublicationOptions(T&& name, uint32_t lifetime) + : name_(std::forward(name)), + content_lifetime_milliseconds_(lifetime) {} + + TRANSPORT_ALWAYS_INLINE const core::Name& getName() const { return name_; } + TRANSPORT_ALWAYS_INLINE uint32_t getLifetime() const { + return content_lifetime_milliseconds_; + } + + private: + core::Name name_; + uint32_t content_lifetime_milliseconds_; + // TODO Signature +}; +} // namespace interface + +} // namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h new file mode 100644 index 000000000..218240f83 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/rtc_socket_producer.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { + +namespace interface { + +class RTCProducerSocket : public ProducerSocket { + public: + RTCProducerSocket(); + ~RTCProducerSocket() = default; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h new file mode 100644 index 000000000..e9e671edd --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CONSUMER_FINISHED 0 +#define CONSUMER_BUSY 1 +#define CONSUMER_RUNNING 2 + +namespace transport { + +namespace implementation { +class ConsumerSocket; +} + +namespace interface { + +using namespace core; + +/** + * @brief Main interface for consumer applications. + * + * The consumer socket is the main interface for a consumer application. + * It allows to retrieve an application data from one/many producers, by + * hiding all the complexity of the transport protocol used underneath. + */ +class ConsumerSocket { + public: + /** + * The ReadCallback is a class which can be used by the transport for both + * querying the application needs and notifying events. + * + * Beware that the methods of this class will be called synchronously while + * the transport is working, so the operations the application is performing + * on the data retrieved should be executed in another thread in an + * asynchronous manner. Blocking one of these callbacks means blocking the + * transport. + */ + class ReadCallback { + public: + virtual ~ReadCallback() = default; + + /** + * This API will specify to the transport whether the buffer should be + * allocated by the application (and then the retrieved content will be + * copied there) or the transport should allocate the buffer and "move" it + * to the application. In other words, if isBufferMovable return true, the + * transport will transfer the ownership of the read buffer to the + * application, without performing an additional copy, while if it returns + * false the transport will use the getReadBuffer API. + * + * By default this method returns true. + * + */ + virtual bool isBufferMovable() noexcept { return true; } + + /** + * This method will be called by the transport when the content is + * available. The application can then allocate its own buffer and provide + * the address to the transport, which will use it for writing the data. + * Note that if the application won't allocate enough memory this method + * will be called several times, until the internal read buffer will be + * emptied. For ensuring this method will be called once, applications + * should allocate at least maxBufferSize() bytes. + * + * @param application_buffer - Pointer to the application's buffer. + * @param max_length - The length of the application buffer. + */ + virtual void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) = 0; + + /** + * This method will be called by the transport after calling getReadBuffer, + * in order to notify the application that length bytes are available in the + * buffer. The max_length size of the buffer could be larger than the actual + * amount of bytes written. + * + * @param length - The number of bytes placed in the buffer. + */ + virtual void readDataAvailable(size_t length) noexcept = 0; + + /** + * This method will be called by the transport for understanding how many + * bytes it should read (at most) before notifying the application. + * + * By default it reads 64 KB. + */ + virtual size_t maxBufferSize() const { return 64 * 1024; } + + /** + * This method will be called by the transport iff (isBufferMovable == + * true). The unique_ptr underlines the fact that the ownership of the + * buffer is being transferred to the application. + * + * @param buffer - The buffer + */ + virtual void readBufferAvailable( + std::unique_ptr &&buffer) noexcept {} + + /** + * readError() will be invoked if an error occurs reading from the + * transport. + * + * @param ec - An error code describing the error. + */ + virtual void readError(const std::error_code ec) noexcept = 0; + + /** + * This callback will be invoked when the whole content is retrieved. The + * transport itself knows when a content is retrieved (since it is not an + * opaque bytestream like TCP), and the transport itself is able to tell + * the application when the transfer is done. + */ + virtual void readSuccess(std::size_t total_size) noexcept = 0; + }; + + /** + * @brief Create a new consumer socket. + * + * @param protocol - The transport protocol to use. So far the following + * transport are supported: + * - CBR: Constant bitrate + * - Raaqm: Based on paper: Optimal multipath congestion control and request + * forwarding in information-centric networks: Protocol design and + * experimentation. G Carofiglio, M Gallo, L Muscariello. Computer Networks + * 110, 104-117 + * - RTC: Real time communication + */ + explicit ConsumerSocket(int protocol); + + /** + * @brief Destroy the consumer socket. + */ + ~ConsumerSocket(); + + /** + * @brief Connect the consumer socket to the underlying hICN forwarder. + */ + void connect(); + + /** + * @brief Check whether consumer socket is active or not. + */ + bool isRunning(); + + /** + * Retrieve a content using the protocol specified in the constructor. + * This function blocks until the whole content is downloaded. + * For monitoring the status of the download, the application MUST set the + * ConsumerRead callback. This callback will be called periodically (depending + * on the needs of the application), allowing the application to save the + * retrieved data. + * + * @param name - The name of the content to retrieve. + * + * @return CONSUMER_BUSY if a pending download exists + * @return CONSUMER_FINISHED when the download finishes + * + * Notice that the fact consume() returns CONSUMER_FINISHED does not imply the + * content retrieval succeeded. This information can be obtained from the + * error code in CONTENT_RETRIEVED callback. + */ + int consume(const Name &name); + int asyncConsume(const Name &name); + + /** + * Verify the packets containing a key after the origin of the key has been + * validated by the client. + * + * @return true if all packets are valid, false otherwise + */ + bool verifyKeyPackets(); + + /** + * Stops the consumer socket. If several downloads are queued (using + * asyncConsume), this call stops just the current one. + */ + void stop(); + + /** + * Resume the download from the same exact point it stopped. + */ + void resume(); + + /** + * Get the io_service which is running the transport protocol event loop. + * + * @return A reference to the internal io_service where the transport protocol + * is running. + */ + asio::io_service &getIoService(); + + int setSocketOption(int socket_option_key, ReadCallback *socket_option_value); + + int getSocketOption(int socket_option_key, + ReadCallback **socket_option_value); + + int setSocketOption(int socket_option_key, double socket_option_value); + + int setSocketOption(int socket_option_key, uint32_t socket_option_value); + + int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value); + + int setSocketOption(int socket_option_key, bool socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerContentObjectCallback socket_option_value); + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback socket_option_value); + + int setSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerInterestCallback socket_option_value); + + int setSocketOption(int socket_option_key, + interface::IcnObserver *socket_option_value); + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value); + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value); + + int setSocketOption(int socket_option_key, + ConsumerTimerCallback socket_option_value); + + int getSocketOption(int socket_option_key, double &socket_option_value); + + int getSocketOption(int socket_option_key, uint32_t &socket_option_value); + + int getSocketOption(int socket_option_key, bool &socket_option_value); + + int getSocketOption(int socket_option_key, Name **socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerContentObjectCallback **socket_option_value); + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationFailedCallback **socket_option_value); + + int getSocketOption( + int socket_option_key, + ConsumerContentObjectVerificationCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerInterestCallback **socket_option_value); + + int getSocketOption(int socket_option_key, IcnObserver **socket_option_value); + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value); + + int getSocketOption(int socket_option_key, std::string &socket_option_value); + + int getSocketOption(int socket_option_key, + ConsumerTimerCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + interface::TransportStatistics **socket_option_value); + + protected: + ConsumerSocket(); + std::unique_ptr socket_; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h new file mode 100644 index 000000000..bcf103b8c --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace transport { + +namespace interface { + +namespace default_values { + +static constexpr uint32_t interest_lifetime = 1001; // milliseconds +static constexpr uint32_t never_expire_time = HICN_MAX_LIFETIME; +static constexpr uint32_t content_object_expiry_time = + never_expire_time; // milliseconds -> 50 seconds +static constexpr uint32_t content_object_packet_size = + 1500; // The ethernet MTU +static constexpr uint32_t producer_socket_output_buffer_size = + 150000; // Content Object +static constexpr uint32_t log_2_default_buffer_size = 12; +static constexpr uint32_t signature_size = 260; // bytes +static constexpr uint32_t key_locator_size = 60; // bytes +static constexpr uint32_t limit_guard = 80; // bytes +static constexpr uint32_t digest_size = 34; // bytes +static constexpr uint32_t max_out_of_order_segments = 3; // content object + +// RAAQM +static constexpr int sample_number = 30; +static constexpr double gamma_value = 1; +static constexpr double beta_value = 0.8; +static constexpr double drop_factor = 0.2; +static constexpr double minimum_drop_probability = 0.00001; +static constexpr int path_id = 0; +static constexpr double rate_alpha = 0.8; + +// Rate estimation +static constexpr uint32_t batch = 50; +static constexpr uint32_t kv = 20; +static constexpr double alpha = 0.8; +static constexpr uint32_t rate_choice = 0; + +// maximum allowed values +static constexpr uint32_t transport_protocol_min_retransmissions = 0; +static constexpr uint32_t transport_protocol_max_retransmissions = 128; +static constexpr uint32_t max_content_object_size = 8096; +static constexpr uint32_t min_window_size = 1; // Interests +static constexpr uint32_t max_window_size = 256 * 2; // Interests + +} // namespace default_values + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h new file mode 100644 index 000000000..7910a4422 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#define SOCKET_OPTION_GET 0 +#define SOCKET_OPTION_NOT_GET 1 +#define SOCKET_OPTION_SET 2 +#define SOCKET_OPTION_NOT_SET 3 +#define SOCKET_OPTION_DEFAULT 12345 + +namespace transport { + +namespace interface { + +typedef enum { + RAAQM = 0, + CBR = 1, + RTC = 2, +} TransportProtocolAlgorithms; + +typedef enum { + INPUT_BUFFER_SIZE = 101, + OUTPUT_BUFFER_SIZE = 102, + NETWORK_NAME = 103, + NAME_SUFFIX = 104, + MAX_INTEREST_RETX = 105, + DATA_PACKET_SIZE = 106, + INTEREST_LIFETIME = 107, + CONTENT_OBJECT_EXPIRY_TIME = 108, + KEY_CONTENT = 110, + MIN_WINDOW_SIZE = 111, + MAX_WINDOW_SIZE = 112, + CURRENT_WINDOW_SIZE = 113, + ASYNC_MODE = 114, + MAKE_MANIFEST = 115, + PORTAL = 116, + RUNNING = 117, + APPLICATION_BUFFER = 118, + HASH_ALGORITHM = 119, + CRYPTO_SUITE = 120, + SIGNER = 121, + VERIFIER = 122, + CERTIFICATE = 123, + VERIFY_SIGNATURE = 124, + STATS_INTERVAL = 125, +} GeneralTransportOptions; + +typedef enum { + SAMPLE_NUMBER = 201, + GAMMA_VALUE = 202, + BETA_VALUE = 203, + DROP_FACTOR = 204, + MINIMUM_DROP_PROBABILITY = 205, + PATH_ID = 206, + RTT_STATS = 207, +} RaaqmTransportOptions; + +typedef enum { + RATE_ESTIMATION_ALPHA = 301, + RATE_ESTIMATION_OBSERVER = 302, + RATE_ESTIMATION_BATCH_PARAMETER = 303, + RATE_ESTIMATION_CHOICE = 304, +} RateEstimationOptions; + +typedef enum { + INTEREST_OUTPUT = 401, + INTEREST_RETRANSMISSION = 402, + INTEREST_EXPIRED = 403, + INTEREST_SATISFIED = 404, + CONTENT_OBJECT_INPUT = 411, + CONTENT_OBJECT_TO_VERIFY = 413, + VERIFICATION_FAILED = 414, + READ_CALLBACK = 415, + STATS_SUMMARY = 416 +} ConsumerCallbacksOptions; + +typedef enum { + INTEREST_INPUT = 501, + INTEREST_DROP = 502, + INTEREST_PASS = 503, + CACHE_HIT = 506, + CACHE_MISS = 508, + NEW_CONTENT_OBJECT = 509, + CONTENT_OBJECT_SIGN = 513, + CONTENT_OBJECT_READY = 510, + CONTENT_OBJECT_OUTPUT = 511, + CONTENT_PRODUCED = 512, +} ProducerCallbacksOptions; + +typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions; + +typedef enum { + VIRTUAL_DOWNLOAD = 701, + USE_CFG_FILE = 702, + STATISTICS +} OtherOptions; + +typedef enum { + SHA_256 = 801, + RSA_256 = 802, +} SignatureType; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/socket_producer.h b/libtransport/includes/hicn/transport/interfaces/socket_producer.h new file mode 100644 index 000000000..3fe99fbd4 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/socket_producer.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace implementation { +class ProducerSocket; +} + +namespace interface { + +using namespace core; + +class ProducerSocket { + public: + explicit ProducerSocket(int protocol = 0); + + virtual ~ProducerSocket(); + + void connect(); + + bool isRunning(); + + uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size, + bool is_last = true, uint32_t start_offset = 0) { + return produce(content_name, utils::MemBuf::copyBuffer(buffer, buffer_size), + is_last, start_offset); + } + + uint32_t produce(Name content_name, std::unique_ptr &&buffer, + bool is_last = true, uint32_t start_offset = 0); + + void produce(ContentObject &content_object); + + void produce(const uint8_t *buffer, size_t buffer_size) { + produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); + } + + void produce(std::unique_ptr &&buffer); + + void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size, + bool is_last = true, uint32_t *start_offset = nullptr); + + void asyncProduce(Name content_name, std::unique_ptr &&buffer, + bool is_last, uint32_t offset, + uint32_t **last_segment = nullptr); + + void asyncProduce(ContentObject &content_object); + + void registerPrefix(const Prefix &producer_namespace); + + void serveForever(); + + void stop(); + + asio::io_service &getIoService(); + + int setSocketOption(int socket_option_key, uint32_t socket_option_value); + + int setSocketOption(int socket_option_key, + std::nullptr_t socket_option_value); + + int setSocketOption(int socket_option_key, bool socket_option_value); + + int setSocketOption(int socket_option_key, Name *socket_option_value); + + int setSocketOption(int socket_option_key, + std::list socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerContentObjectCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerInterestCallback socket_option_value); + + int setSocketOption(int socket_option_key, + ProducerContentCallback socket_option_value); + + int setSocketOption(int socket_option_key, HashAlgorithm socket_option_value); + + int setSocketOption(int socket_option_key, + utils::CryptoSuite socket_option_value); + + int setSocketOption( + int socket_option_key, + const std::shared_ptr &socket_option_value); + + int setSocketOption(int socket_option_key, + const std::string &socket_option_value); + + int getSocketOption(int socket_option_key, uint32_t &socket_option_value); + + int getSocketOption(int socket_option_key, bool &socket_option_value); + + int getSocketOption(int socket_option_key, + std::list &socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerContentObjectCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerContentCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + ProducerInterestCallback **socket_option_value); + + int getSocketOption(int socket_option_key, + HashAlgorithm &socket_option_value); + + int getSocketOption(int socket_option_key, + utils::CryptoSuite &socket_option_value); + + int getSocketOption(int socket_option_key, + std::shared_ptr &socket_option_value); + + int getSocketOption(int socket_option_key, std::string &socket_option_value); + + protected: + ProducerSocket(bool); + std::unique_ptr socket_; +}; + +} // namespace interface + +} // namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/statistics.h b/libtransport/includes/hicn/transport/interfaces/statistics.h new file mode 100644 index 000000000..26831fbf1 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/statistics.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace transport { + +namespace interface { + +class IcnObserver { + public: + virtual ~IcnObserver(){}; + + virtual void notifyStats(double throughput) = 0; + virtual void notifyDownloadTime(double downloadTime) = 0; +}; + +class TransportStatistics { + static constexpr double default_alpha = 0.7; + + public: + TransportStatistics(double alpha = default_alpha) + : retx_count_(0), + bytes_received_(0), + average_rtt_(0), + avg_window_size_(0), + interest_tx_(0), + alpha_(alpha), + loss_ratio_(0.0), + queuing_delay_(0.0) {} + + TRANSPORT_ALWAYS_INLINE void updateRetxCount(uint64_t retx) { + retx_count_ += retx; + } + + TRANSPORT_ALWAYS_INLINE void updateBytesRecv(uint64_t bytes) { + bytes_received_ += bytes; + } + + TRANSPORT_ALWAYS_INLINE void updateAverageRtt(uint64_t rtt) { + average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt)); + } + + TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) { + avg_window_size_ = + (alpha_ * avg_window_size_) + ((1. - alpha_) * current_window); + } + + TRANSPORT_ALWAYS_INLINE void updateInterestTx(uint64_t int_tx) { + interest_tx_ += int_tx; + } + + TRANSPORT_ALWAYS_INLINE void updateLossRatio(double loss_ratio) { + loss_ratio_ = loss_ratio; + } + + TRANSPORT_ALWAYS_INLINE void updateQueuingDelay(double queuing_delay) { + queuing_delay_ = queuing_delay; + } + + TRANSPORT_ALWAYS_INLINE uint64_t getRetxCount() const { return retx_count_; } + + TRANSPORT_ALWAYS_INLINE uint64_t getBytesRecv() const { + return bytes_received_; + } + + TRANSPORT_ALWAYS_INLINE double getAverageRtt() const { return average_rtt_; } + + TRANSPORT_ALWAYS_INLINE double getAverageWindowSize() const { + return avg_window_size_; + } + + TRANSPORT_ALWAYS_INLINE uint64_t getInterestTx() const { + return interest_tx_; + } + + TRANSPORT_ALWAYS_INLINE double getLossRatio() const { return loss_ratio_; } + + TRANSPORT_ALWAYS_INLINE double getQueuingDelay() const { + return queuing_delay_; + } + + TRANSPORT_ALWAYS_INLINE void reset() { + retx_count_ = 0; + bytes_received_ = 0; + average_rtt_ = 0; + avg_window_size_ = 0; + interest_tx_ = 0; + loss_ratio_ = 0; + } + + private: + uint64_t retx_count_; + uint64_t bytes_received_; + double average_rtt_; + double avg_window_size_; + uint64_t interest_tx_; + double alpha_; + double loss_ratio_; + double queuing_delay_; +}; + +} // namespace interface + +} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/verification_policy.h b/libtransport/includes/hicn/transport/interfaces/verification_policy.h new file mode 100644 index 000000000..cb5140ac1 --- /dev/null +++ b/libtransport/includes/hicn/transport/interfaces/verification_policy.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace transport { +namespace interface { + +/** + * This policy allows the application to tell the transport what to do in case + * the verification of a content object fails. + */ +enum class VerificationPolicy : std::uint8_t { + DROP_PACKET, + ACCEPT_PACKET, + ABORT_SESSION +}; +} // namespace interface +} // namespace transport \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/CMakeLists.txt b/libtransport/includes/hicn/transport/portability/CMakeLists.txt new file mode 100644 index 000000000..469b11192 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h + ${CMAKE_CURRENT_SOURCE_DIR}/portability.h +) + +list(APPEND SOURCE_FILES + "" +) + +if(WIN32) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/win_portability.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/c_portability.h b/libtransport/includes/hicn/transport/portability/c_portability.h new file mode 100644 index 000000000..71e976a81 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/c_portability.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// noinline +#ifdef _MSC_VER +#define TRANSPORT_NOINLINE __declspec(noinline) +#elif defined(__clang__) || defined(__GNUC__) +#define TRANSPORT_NOINLINE __attribute__((__noinline__)) +#else +#define TRANSPORT_NOINLINE +#endif + +// always inline +#ifdef _MSC_VER +#define TRANSPORT_ALWAYS_INLINE __forceinline +#elif defined(__clang__) || defined(__GNUC__) +#define TRANSPORT_ALWAYS_INLINE inline __attribute__((__always_inline__)) +#else +#define TRANSPORT_ALWAYS_INLINE inline +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/portability.h b/libtransport/includes/hicn/transport/portability/portability.h new file mode 100644 index 000000000..1d97a346e --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/portability.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef _WIN32 +#include +#endif + +#include + +#include +#include + +namespace portability { + +constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__; +constexpr bool big_endian_arch = !little_endian_arch; + +#if defined(__GNUC__) +#define _TRANSPORT_GNU_DISABLE_WARNING(warning) #warning +#define TRANSPORT_GNU_DISABLE_WARNING(warning) \ + _Pragma(_TRANSPORT_GNU_DISABLE_WARNING(GCC diagnostic ignored warning)) + +#ifdef __clang__ +#define TRANSPORT_CLANG_DISABLE_WARNING(warning) \ + TRANSPORT_GNU_DISABLE_WARNING(warning) +#define TRANSPORT_GCC_DISABLE_WARNING(warning) +#else +#define TRANSPORT_CLANG_DISABLE_WARNING(warning) +#define TRANSPORT_GCC_DISABLE_WARNING(warning) \ + TRANSPORT_GNU_DISABLE_WARNING(warning) +#endif +#endif + +} // namespace portability diff --git a/libtransport/includes/hicn/transport/portability/win_portability.h b/libtransport/includes/hicn/transport/portability/win_portability.h new file mode 100644 index 000000000..65d949291 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/win_portability.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __ORDER_LITTLE_ENDIAN__ 0x41424344UL +#define __ORDER_BIG_ENDIAN__ 0x44434241UL +#define __BYTE_ORDER__ ('ABCD') +#undef DELETE + +#define HAVE_STRUCT_TIMESPEC +#include \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/CMakeLists.txt b/libtransport/includes/hicn/transport/security/CMakeLists.txt new file mode 100644 index 000000000..58a96780b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/signer.h + ${CMAKE_CURRENT_SOURCE_DIR}/verifier.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hasher.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/identity.h + ${CMAKE_CURRENT_SOURCE_DIR}/key_id.h +) + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hash.h b/libtransport/includes/hicn/transport/security/crypto_hash.h new file mode 100644 index 000000000..5a58f258b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hash.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +extern "C" { +#include +}; + +#include +#include + +namespace utils { + +class CryptoHasher; + +struct EnumClassHash { + template + std::size_t operator()(T t) const { + return static_cast(t); + } +}; + +static std::unordered_map + hash_size_map = {{CryptoHashType::SHA_256, 32}, + {CryptoHashType::CRC32C, 4}, + {CryptoHashType::SHA_512, 64}}; + +class Signer; +class Verifier; + +class CryptoHash { + friend class CryptoHasher; + friend class Signer; + friend class Verifier; + + public: + CryptoHash() : hash_(nullptr) {} + + CryptoHash(const CryptoHash& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + } + + CryptoHash(CryptoHash&& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + } + + template + CryptoHash(const T* buffer, std::size_t length, CryptoHashType hash_type) { + hash_ = parcCryptoHash_CreateFromArray( + static_cast(hash_type), buffer, length); + } + + ~CryptoHash() { + if (hash_) { + parcCryptoHash_Release(&hash_); + } + } + + CryptoHash& operator=(const CryptoHash& other) { + if (other.hash_) { + hash_ = parcCryptoHash_Acquire(other.hash_); + } + + return *this; + } + + template + utils::Array getDigest() const { + return utils::Array( + static_cast(parcBuffer_Overlay(parcCryptoHash_GetDigest(hash_), 0)), + parcBuffer_Remaining(parcCryptoHash_GetDigest(hash_))); + } + + CryptoHashType getType() { + return static_cast(parcCryptoHash_GetDigestType(hash_)); + } + + template + static bool compareBinaryDigest(const T* digest1, const T* digest2, + CryptoHashType hash_type) { + if (hash_size_map.find(hash_type) == hash_size_map.end()) { + return false; + } + + return !static_cast( + std::memcmp(digest1, digest2, hash_size_map[hash_type])); + } + + TRANSPORT_ALWAYS_INLINE void display() { + parcBuffer_Display(parcCryptoHash_GetDigest(hash_), 2); + } + + private: + PARCCryptoHash* hash_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hash_type.h b/libtransport/includes/hicn/transport/security/crypto_hash_type.h new file mode 100644 index 000000000..b7597e208 --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hash_type.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern "C" { +#include +}; + +namespace utils { + +enum class CryptoHashType : uint8_t { + SHA_256 = PARCCryptoHashType_SHA256, + SHA_512 = PARCCryptoHashType_SHA512, + CRC32C = PARCCryptoHashType_CRC32C, + NULL_HASH = PARCCryptoHashType_NULL +}; + +} \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_hasher.h b/libtransport/includes/hicn/transport/security/crypto_hasher.h new file mode 100644 index 000000000..9367c3bc8 --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_hasher.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +extern "C" { +#include +}; + +namespace utils { + +class CryptoHasher { + public: + CryptoHasher(CryptoHashType hash_type) + : hasher_(parcCryptoHasher_Create( + static_cast(hash_type))), + managed_(true) {} + + CryptoHasher(PARCCryptoHasher* hasher) : hasher_(hasher), managed_(false) {} + + ~CryptoHasher() { + if (managed_) { + parcCryptoHasher_Release(&hasher_); + } + } + + CryptoHasher& init() { + if (parcCryptoHasher_Init(hasher_) == -1) { + throw errors::RuntimeException("Cryptohash init failed."); + } + + return *this; + } + + template + CryptoHasher& updateBytes(const T* buffer, std::size_t length) { + if (parcCryptoHasher_UpdateBytes(hasher_, buffer, length) == -1) { + throw errors::RuntimeException("Cryptohash updateBytes failed."); + } + return *this; + } + + CryptoHash finalize() { + CryptoHash hash; + hash.hash_ = parcCryptoHasher_Finalize(hasher_); + return hash; + } + + private: + PARCCryptoHasher* hasher_; + bool managed_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/security/crypto_suite.h b/libtransport/includes/hicn/transport/security/crypto_suite.h new file mode 100644 index 000000000..017938f8f --- /dev/null +++ b/libtransport/includes/hicn/transport/security/crypto_suite.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern "C" { +#include +}; + +#include + +namespace utils { + +enum class CryptoSuite : uint8_t { + RSA_SHA256 = PARCCryptoSuite_RSA_SHA256, + DSA_SHA256 = PARCCryptoSuite_DSA_SHA256, + RSA_SHA512 = PARCCryptoSuite_RSA_SHA512, + HMAC_SHA256 = PARCCryptoSuite_HMAC_SHA256, + HMAC_SHA512 = PARCCryptoSuite_HMAC_SHA512, + NULL_CRC32C = PARCCryptoSuite_NULL_CRC32C, + ECDSA_256K1 = PARCCryptoSuite_ECDSA_SHA256, + UNKNOWN = PARCCryptoSuite_UNKNOWN +}; +} diff --git a/libtransport/includes/hicn/transport/security/identity.h b/libtransport/includes/hicn/transport/security/identity.h new file mode 100644 index 000000000..c5d4b975d --- /dev/null +++ b/libtransport/includes/hicn/transport/security/identity.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +extern "C" { +#include +#include +#include +}; + +#include + +namespace utils { + +class Identity { + public: + Identity(const std::string &keystore_name, + const std::string &keystore_password, CryptoSuite suite, + unsigned int signature_length, unsigned int validity_days, + const std::string &subject_name); + + Identity(const Identity &other); + + Identity(std::string &file_name, std::string &password, + transport::core::HashAlgorithm hash_algorithm); + + ~Identity(); + + static Identity generateIdentity(const std::string &subject_name); + + std::string getFileName(); + + std::string getPassword(); + + std::shared_ptr getSigner(); + + size_t getSignatureLength() const; + + private: + PARCIdentity *identity_; + std::shared_ptr signer_; + transport::core::HashAlgorithm hash_algorithm_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/security/key_id.h b/libtransport/includes/hicn/transport/security/key_id.h new file mode 100644 index 000000000..d67b73d7a --- /dev/null +++ b/libtransport/includes/hicn/transport/security/key_id.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace utils { + +using KeyId = std::pair; + +} diff --git a/libtransport/includes/hicn/transport/security/signer.h b/libtransport/includes/hicn/transport/security/signer.h new file mode 100644 index 000000000..31b21462b --- /dev/null +++ b/libtransport/includes/hicn/transport/security/signer.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +extern "C" { +#include +#include +#include +#include +#include +} + +namespace utils { + +using Packet = transport::core::Packet; + +/** + * A signer can use a single key (asymmetric or symmetric) to sign a packet. + */ +class Signer { + friend class Identity; + + public: + /** + * Create a Signer + * + * @param keyStore A keystore containing a private key or simmetric key to + * use to sign packet with this Signer. + * @param suite CryptoSuite to use to verify the signature + */ + Signer(PARCKeyStore *keyStore, CryptoSuite suite); + + /** + * Create a Signer + * + * @param passphrase A string from which the symmetric key will be derived + * @param suite CryptoSuite to use to verify the signature + */ + Signer(const std::string &passphrase, CryptoSuite suite); + + Signer(const PARCSigner *signer, CryptoSuite suite); + + Signer(const PARCSigner *signer); + + ~Signer(); + + /** + * @brief Sign a packet + * + * This method is general and must be used for Public-private key signature, + * HMAC and CRC. + * + * @param packet A pointer to the header of the packet to sign. Mutable + * field in the packet must be set to 0. + * @param key_id Indentifier of the key to use to generate the signature. + */ + void sign(Packet &packet); + + size_t getSignatureLength(); + + PARCKeyStore *getKeyStore(); + + private: + PARCBufferComposer *composer_ = nullptr; + PARCBuffer *key_buffer_ = nullptr; + PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; + PARCSigner *signer_ = nullptr; + PARCSignature *signature_ = nullptr; + PARCKeyId *key_id_ = nullptr; + CryptoSuite suite_; + size_t signature_length_; + static uint8_t zeros[200]; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/security/verifier.h b/libtransport/includes/hicn/transport/security/verifier.h new file mode 100644 index 000000000..7ec6e7eda --- /dev/null +++ b/libtransport/includes/hicn/transport/security/verifier.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +} + +namespace utils { + +using Packet = transport::core::Packet; + +/** + * A verifier holds a crypto cache that contains all the keys to use for + * verify signatures/hmacs. + */ +class Verifier { + public: + Verifier(); + + ~Verifier(); + + /** + * @brief Check if a key is already in this Verifier. + * + * A PARCVerifier contains a CryptoCache with a set of key to use for + * verification purposes. + * + * @param keyId Identifier of the key to match in the CryptoCache of the + * Verifier. + * @return true if the key is found, false otherwise. + */ + bool hasKey(PARCKeyId *keyId); + + /** + * @brief Add a key to this Verifier + * + * @param key to add + * @return true if the key was added successfully, false otherwise. + */ + bool addKey(PARCKey *key); + + PARCKeyId *addKeyFromPassphrase(const std::string &passphrase, + CryptoSuite suite); + + PARCKeyId *addKeyFromCertificate(const std::string &file_name); + + /** + * @brief Verify a Signature + * + * This method is general and must be used for Public-private key signature, + * HMAC and CRC. + * + * @param signature A pointer to the buffer holding the signature + * @param sign_len Lenght of the signature (must be consistent with the type + * of the key) + * @param bufferSigned A pointer to the packet header signed with + * signature. Mutable fields and the signature field in the packet must be + * set to 0 + * @param buf_len Lenght of bufferSigned + * @param suite CryptoSuite to use to verify the signature + * @param key_id Indentifier of the key to use to verify the signature. The + * key must be already present in the Verifier. + */ + int verify(const Packet &packet); + + CryptoHash getPacketHash(const Packet &packet, + std::shared_ptr hasher); + + private: + PARCVerifier *verifier_ = nullptr; + PARCCertificateFactory *factory_ = nullptr; + PARCCertificate *certificate_ = nullptr; + PARCKeyId *keyId_ = nullptr; + PARCKey *key_ = nullptr; + PARCBuffer *key_buffer_ = nullptr; + PARCSymmetricKeyStore *symmetricKeyStore_ = nullptr; + PARCSigner *signer_ = nullptr; + PARCBufferComposer *composer_ = nullptr; + static uint8_t zeros[200]; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/CMakeLists.txt b/libtransport/includes/hicn/transport/utils/CMakeLists.txt new file mode 100644 index 000000000..396bd06d6 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/array.h + ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.h + ${CMAKE_CURRENT_SOURCE_DIR}/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/uri.h + ${CMAKE_CURRENT_SOURCE_DIR}/chrono_typedefs.h + ${CMAKE_CURRENT_SOURCE_DIR}/branch_prediction.h + ${CMAKE_CURRENT_SOURCE_DIR}/ring_buffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/literals.h + ${CMAKE_CURRENT_SOURCE_DIR}/conversions.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux.h + ${CMAKE_CURRENT_SOURCE_DIR}/log.h + ${CMAKE_CURRENT_SOURCE_DIR}/object_pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/membuf.h + ${CMAKE_CURRENT_SOURCE_DIR}/spinlock.h +) + +if(NOT WIN32) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.h + ) +endif() + +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/array.h b/libtransport/includes/hicn/transport/utils/array.h new file mode 100644 index 000000000..7c0ed65d8 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/array.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace utils { + +template +class Array { + public: + explicit Array(const T *array, size_t size) : array_(array), size_(size) { + this->array_ = array; + this->size_ = size; + } + + Array() : array_(nullptr), size_(0) { + this->array_ = nullptr; + this->size_ = 0; + } + + TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; } + + TRANSPORT_ALWAYS_INLINE T *writableData() const { + return const_cast(array_); + } + + TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; } + + TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) { + array_ = data; + return *this; + } + + TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) { + size_ = size; + return *this; + } + + TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; } + + private: + const T *array_; + std::size_t size_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/branch_prediction.h b/libtransport/includes/hicn/transport/utils/branch_prediction.h new file mode 100644 index 000000000..8cbfaca76 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/branch_prediction.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#undef TRANSPORT_EXPECT_TRUE +#undef TRANSPORT_EXPECT_FALSE + +#ifndef _WIN32 +#define TRANSPORT_EXPECT_TRUE(x) __builtin_expect((x), 1) +#define TRANSPORT_EXPECT_FALSE(x) __builtin_expect((x), 0) +#else +#define TRANSPORT_EXPECT_TRUE(x) (x) +#define TRANSPORT_EXPECT_FALSE(x) (x) +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h new file mode 100644 index 000000000..8f28e763c --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace utils { + +using SteadyClock = std::chrono::steady_clock; +using TimePoint = SteadyClock::time_point; +using Milliseconds = std::chrono::milliseconds; +using Microseconds = std::chrono::microseconds; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/conversions.h b/libtransport/includes/hicn/transport/utils/conversions.h new file mode 100644 index 000000000..24b529206 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/conversions.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace utils { + +static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress( + const std::string& mac_address, uint8_t* mac_byte_array) { + const char* mac = mac_address.c_str(); + + sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0], + &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3], + &mac_byte_array[4], &mac_byte_array[5]); + + return 0; +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/daemonizator.h b/libtransport/includes/hicn/transport/utils/daemonizator.h new file mode 100644 index 000000000..028d74865 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/daemonizator.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef _WIN32 + +#include +namespace utils { + +class Daemonizator { + public: + static void daemonize(bool close_fds = true); +}; + +} // namespace utils + +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/hash.h b/libtransport/includes/hicn/transport/utils/hash.h new file mode 100644 index 000000000..6815ca4bf --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/hash.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace utils { + +namespace hash { + +/* + * Fowler / Noll / Vo (FNV) Hash + * http://www.isthe.com/chongo/tech/comp/fnv/ + */ + +const uint32_t FNV_32_HASH_START = 2166136261UL; +const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s, + uint32_t hash = FNV_32_HASH_START) { + for (; *s; ++s) { + hash += + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); + hash ^= *s; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n, + uint32_t hash = FNV_32_HASH_START) { + // forcing signed char, since other platforms can use unsigned + const signed char *char_buf = reinterpret_cast(buf); + + for (size_t i = 0; i < n; ++i) { + hash += + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); + hash ^= char_buf[i]; + } + + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str, + uint32_t hash = FNV_32_HASH_START) { + return fnv32_buf(str.data(), str.size(), hash); +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s, + uint64_t hash = FNV_64_HASH_START) { + for (; *s; ++s) { + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + + (hash << 8) + (hash << 40); + hash ^= *s; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n, + uint64_t hash = FNV_64_HASH_START) { + // forcing signed char, since other platforms can use unsigned + const signed char *char_buf = reinterpret_cast(buf); + + for (size_t i = 0; i < n; ++i) { + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + + (hash << 8) + (hash << 40); + hash ^= char_buf[i]; + } + return hash; +} + +TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str, + uint64_t hash = FNV_64_HASH_START) { + return fnv64_buf(str.data(), str.size(), hash); +} + +} // namespace hash + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/linux.h b/libtransport/includes/hicn/transport/utils/linux.h new file mode 100644 index 000000000..5820528e1 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/linux.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef __linux__ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define LINK_LOCAL_PREFIX 0xfe80 + +namespace utils { + +static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress( + const std::string &interface_name, struct sockaddr_in6 *address) { + struct ifaddrs *ifap, *ifa; + char addr[INET6_ADDRSTRLEN]; + + getifaddrs(&ifap); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + strcmp(ifa->ifa_name, interface_name.c_str()) == 0) { + struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr; + uint16_t prefix = 0; + memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t)); + + if (htons(LINK_LOCAL_PREFIX) != prefix) { + *address = *(struct sockaddr_in6 *)ifa->ifa_addr; + getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, + sizeof(addr), NULL, 0, NI_NUMERICHOST); + TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr); + } + } + } + + freeifaddrs(ifap); + + return 0; +} + +} // namespace utils + +#endif // __linux__ \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/literals.h b/libtransport/includes/hicn/transport/utils/literals.h new file mode 100644 index 000000000..bd00e0a58 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/literals.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64( + unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) { + return static_cast(value); +} + +TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) { + return static_cast(value); +} \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/log.h b/libtransport/includes/hicn/transport/utils/log.h new file mode 100644 index 000000000..3c4f1277a --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/log.h @@ -0,0 +1,1057 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 wonder-mice + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +/* To detect incompatible changes you can define TRANSPORT_LOG_VERSION_REQUIRED + * to be the current value of TRANSPORT_LOG_VERSION before including this file + * (or via compiler command line): + * + * #define TRANSPORT_LOG_VERSION_REQUIRED 4 + * #include + * + * Compilation will fail when included file has different version. + */ +#define TRANSPORT_LOG_VERSION 4 +#if defined(TRANSPORT_LOG_VERSION_REQUIRED) +#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION +#error different transport_log version required +#endif +#endif + +/* Log level guideline: + * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely + * unexpected. Process can't continue and must be terminated. Example: division + * by zero, unexpected modifications from other thread. + * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected. + * The process is able to recover and continue execution. Example: out of memory + * (could also be FATAL if not handled properly). + * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen + * and significantly changes application behavior for some period of time. + * Example: configuration file not found, auth error. + * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state + * transition. + * Example: app started, user logged in. + * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct + * the execution path. Usually disabled in release builds. + * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release + * builds. + * + * *Ideally*, log file of debugged, well tested, production ready application + * should be empty or very small. Choosing a right log level is as important as + * providing short and self descriptive log message. + */ +#define TRANSPORT_LOG_VERBOSE 1 +#define TRANSPORT_LOG_DEBUG 2 +#define TRANSPORT_LOG_INFO 3 +#define TRANSPORT_LOG_WARN 4 +#define TRANSPORT_LOG_ERROR 5 +#define TRANSPORT_LOG_FATAL 6 +#define TRANSPORT_LOG_NONE 0xFF + +/* "Current" log level is a compile time check and has no runtime overhead. Log + * level that is below current log level it said to be "disabled". Otherwise, + * it's "enabled". Log messages that are disabled has no runtime overhead - they + * are converted to no-op by preprocessor and then eliminated by compiler. + * Current log level is configured per compilation module (.c/.cpp/.m file) by + * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL + * has higer priority and when defined overrides value provided by + * TRANSPORT_LOG_DEF_LEVEL. + * + * Common practice is to define default current log level with + * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp, + * etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO + * + * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE + * #include + * + * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then + * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and + * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined). + */ +#if defined(TRANSPORT_LOG_LEVEL) +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL +#elif defined(TRANSPORT_LOG_DEF_LEVEL) +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO +#else +#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG +#endif +#endif + +/* "Output" log level is a runtime check. When log level is below output log + * level it said to be "turned off" (or just "off" for short). Otherwise it's + * "turned on" (or just "on"). Log levels that were "disabled" (see + * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but + * "enabled" log levels could be "turned off". Only messages with log level + * which is "turned on" will reach output facility. All other messages will be + * ignored (and their arguments will not be evaluated). Output log level is a + * global property and configured per process using + * transport_log_set_output_level() function which can be called at any time. + * + * Though in some cases it could be useful to configure output log level per + * compilation module or per library. There are two ways to achieve that: + * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired + * output log level. + * - Copy transport_log.h and transport_log.c files into your library and build + * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See + * TRANSPORT_LOG_LIBRARY_PREFIX for more details. + * + * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that + * corresponds to desired output log level. Use it only when compilation module + * is required to have output log level which is different from global output + * log level set by transport_log_set_output_level() function. For other cases, + * consider defining TRANSPORT_LOG_LEVEL or using + * transport_log_set_output_level() function. + * + * Example: + * + * #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level + * #include + * static int g_module_log_level = TRANSPORT_LOG_INFO; + * static void foo() { + * TRANSPORT_LOGI("Will check g_module_log_level for output log level"); + * } + * void debug_log(bool on) { + * g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO; + * } + * + * Note on performance. This expression will be evaluated each time message is + * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL + * for details). Keep this expression as simple as possible, otherwise it will + * not only add runtime overhead, but also will increase size of call site + * (which will result in larger executable). The prefered way is to use integer + * variable (as in example above). If structure must be used, log_level field + * must be the first field in this structure: + * + * #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level) + * #include + * struct config { + * int log_level; + * unsigned other_field; + * [...] + * }; + * static config g_config = {TRANSPORT_LOG_INFO, 0, ...}; + * + * This allows compiler to generate more compact load instruction (no need to + * specify offset since it's zero). Calling a function to get output log level + * is generaly a bad idea, since it will increase call site size and runtime + * overhead even further. + */ +#if defined(TRANSPORT_LOG_OUTPUT_LEVEL) +#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL +#else +#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl +#endif + +/* "Tag" is a compound string that could be associated with a log message. It + * consists of tag prefix and tag (both are optional). + * + * Tag prefix is a global property and configured per process using + * transport_log_set_tag_prefix() function. Tag prefix identifies context in + * which component or module is running (e.g. process name). For example, the + * same library could be used in both client and server processes that work on + * the same machine. Tag prefix could be used to easily distinguish between + * them. For more details about tag prefix see transport_log_set_tag_prefix() + * function. Tag prefix + * + * Tag identifies component or module. It is configured per compilation module + * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG. + * TRANSPORT_LOG_TAG has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to + * (const char *), so for strings double quotes must be used. + * + * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g. + * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\" + * + * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_TAG "MAIN" + * #include + * + * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will + * be added to the log message (tag prefix still could be added though). + * + * Output example: + * + * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1 + * | | + * | +- tag (e.g. module) + * +- tag prefix (e.g. process name) + */ +#if defined(TRANSPORT_LOG_TAG) +#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG +#elif defined(TRANSPORT_LOG_DEF_TAG) +#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG +#else +#define _TRANSPORT_LOG_TAG 0 +#endif + +/* Source location is part of a log line that describes location (function or + * method name, file name and line number, e.g. "runloop@main.cpp:68") of a + * log statement that produced it. + * Source location formats are: + * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line. + * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and + * line number, e.g. "@main.cpp:68"). + * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or + * method name, file and line number, e.g. "runloop@main.cpp:68"). + */ +#define TRANSPORT_LOG_SRCLOC_NONE 0 +#define TRANSPORT_LOG_SRCLOC_SHORT 1 +#define TRANSPORT_LOG_SRCLOC_LONG 2 + +/* Source location format is configured per compilation module (.c/.cpp/.m + * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC. + * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_SRCLOC. + * + * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in + * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire + * project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG + * + * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m + * files before including transport_log.h: + * + * #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE + * #include + * + * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then + * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) + * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined). + */ +#if defined(TRANSPORT_LOG_SRCLOC) +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC +#elif defined(TRANSPORT_LOG_DEF_SRCLOC) +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE +#else +#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG +#endif +#endif +#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC +#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION +#else +#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0 +#endif + +/* Censoring provides conditional logging of secret information, also known as + * Personally Identifiable Information (PII) or Sensitive Personal Information + * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled + * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked + * as "secrets" will be ignored and will have zero overhead (arguments also will + * not be evaluated). + */ +#define TRANSPORT_LOG_CENSORED 1 +#define TRANSPORT_LOG_UNCENSORED 0 + +/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining + * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING. + * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value + * provided by TRANSPORT_LOG_DEF_CENSORING. + * + * Common practice is to define default censoring with + * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt, + * gyp, etc.) for the entire project or target: + * + * CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED + * + * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m + * files before including transport_log.h (consider doing it only for debug + * purposes and be very careful not to push such temporary changes to source + * control): + * + * #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED + * #include + * + * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are + * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds + * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not + * defined). + */ +#if defined(TRANSPORT_LOG_CENSORING) +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING +#elif defined(TRANSPORT_LOG_DEF_CENSORING) +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING +#else +#ifdef NDEBUG +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED +#else +#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED +#endif +#endif + +/* Check censoring at compile time. Evaluates to true when censoring is disabled + * (i.e. when secrets will be logged). For example: + * + * #if TRANSPORT_LOG_SECRETS + * char ssn[16]; + * getSocialSecurityNumber(ssn); + * TRANSPORT_LOGI("Customer ssn: %s", ssn); + * #endif + * + * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single + * log statement. + */ +#define TRANSPORT_LOG_SECRETS \ + (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING) + +/* Static (compile-time) initialization support allows to configure logging + * before entering main() function. This mostly useful in C++ where functions + * and methods could be called during initialization of global objects. Those + * functions and methods could record log messages too and for that reason + * static initialization of logging configuration is customizable. + * + * Macros below allow to specify values to use for initial configuration: + * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none) + * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see + * TRANSPORT_LOG_MEM_WIDTH in transport_log.c) + * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: + * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in + * transport_log.c) + * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level + * (default: 0 - all levals are "turned on") + * + * For example, in log_config.c: + * + * #include + * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp"; + * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH}; + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD, + * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = + * TRANSPORT_LOG_INFO; + * + * However, to use any of those macros transport_log library must be compiled + * with following macros defined: + * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define + * TRANSPORT_LOG_EXTERN_TAG_PREFIX + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define + * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define + * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT + * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define + * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL + * + * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX + * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used + * exactly once somewhere. Otherwise build will fail with link error (undefined + * symbol). + */ +#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix +#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \ + transport_log_format _transport_log_global_format +#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \ + transport_log_output _transport_log_global_output +#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \ + int _transport_log_global_output_lvl + +/* Pointer to global format options. Direct modification is not allowed. Use + * transport_log_set_mem_width() instead. Could be used to initialize + * transport_log_spec structure: + * + * const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD, + * output_callback, 0}; const transport_log_spec g_spec = + * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec, + * "Hello"); + */ +#define TRANSPORT_LOG_GLOBAL_FORMAT \ + ((const transport_log_format *)&_transport_log_global_format) + +/* Pointer to global output variable. Direct modification is not allowed. Use + * transport_log_set_output_v() or transport_log_set_output_p() instead. Could + * be used to initialize transport_log_spec structure: + * + * const transport_log_format g_format = {40}; + * const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT}; + * TRANSPORT_LOGI_AUX(&g_spec, "Hello"); + */ +#define TRANSPORT_LOG_GLOBAL_OUTPUT \ + ((const transport_log_output *)&_transport_log_global_output) + +/* When defined, all library symbols produced by linker will be prefixed with + * provided value. That allows to use transport_log library privately in another + * libraries without exposing transport_log symbols in their original form (to + * avoid possible conflicts with other libraries / components that also could + * use transport_log for logging). Value must be without quotes, for example: + * + * CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_ + * + * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when + * building transport_log library AND it also must be defined to the same value + * when building a library that uses it. For example, consider fictional + * KittyHttp library that wants to use transport_log for logging. First approach + * that could be taken is to add transport_log.h and transport_log.c to the + * KittyHttp's source code tree directly. In that case it will be enough just to + * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script: + * + * // KittyHttp/CMakeLists.txt + * target_compile_definitions(KittyHttp PRIVATE + * "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_") + * + * If KittyHttp doesn't want to include transport_log source code in its source + * tree and wants to build transport_log as a separate library than + * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined + * to KittyHttp_ AND KittyHttp library itself also needs to define + * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build + * script, as in example above, or by providing a wrapper header that KittyHttp + * library will need to use instead of transport_log.h: + * + * // KittyHttpLogging.h + * #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_ + * #include + * + * Regardless of the method chosen, the end result is that transport_log symbols + * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say + * DogeBrowser) also uses transport_log for logging, they will not interferer + * with each other. Both will have their own log level, output facility, format + * options etc. + */ +#ifdef TRANSPORT_LOG_LIBRARY_PREFIX +#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name +#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name) +#define _TRANSPORT_LOG_DECOR(name) \ + _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name) + +#define transport_log_set_tag_prefix \ + _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix) +#define transport_log_set_mem_width \ + _TRANSPORT_LOG_DECOR(transport_log_set_mem_width) +#define transport_log_set_output_level \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_level) +#define transport_log_set_output_v \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_v) +#define transport_log_set_output_p \ + _TRANSPORT_LOG_DECOR(transport_log_set_output_p) +#define transport_log_out_stderr_callback \ + _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback) +#define _transport_log_tag_prefix \ + _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix) +#define _transport_log_global_format \ + _TRANSPORT_LOG_DECOR(_transport_log_global_format) +#define _transport_log_global_output \ + _TRANSPORT_LOG_DECOR(_transport_log_global_output) +#define _transport_log_global_output_lvl \ + _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl) +#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d) +#define _transport_log_write_aux_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d) +#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write) +#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux) +#define _transport_log_write_mem_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d) +#define _transport_log_write_mem_aux_d \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d) +#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem) +#define _transport_log_write_mem_aux \ + _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux) +#define _transport_log_stderr_spec \ + _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec) +#endif + +#if defined(__printflike) +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ + __printflike(str_index, first_to_check) +#elif defined(__GNUC__) +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \ + __attribute__((format(__printf__, str_index, first_to_check))) +#else +#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) +#endif + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__) +#define _TRANSPORT_LOG_FUNCTION __FUNCTION__ +#else +#define _TRANSPORT_LOG_FUNCTION __func__ +#endif + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define _TRANSPORT_LOG_INLINE __inline +#define _TRANSPORT_LOG_IF(cond) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \ + __pragma(warning(pop)) +#define _TRANSPORT_LOG_WHILE(cond) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \ + __pragma(warning(pop)) +#else +#define _TRANSPORT_LOG_INLINE inline +#define _TRANSPORT_LOG_IF(cond) if (cond) +#define _TRANSPORT_LOG_WHILE(cond) while (cond) +#endif +#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0) +#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Set tag prefix. Prefix will be separated from the tag with dot ('.'). + * Use 0 or empty string to disable (default). Common use is to set it to + * the process (or build target) name (e.g. to separate client and server + * processes). Function will NOT copy provided prefix string, but will store the + * pointer. Hence specified prefix string must remain valid. See + * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() + * function. See TRANSPORT_LOG_TAG for more information about tag and tag + * prefix. + */ +void transport_log_set_tag_prefix(const char *const prefix); + +/* Set number of bytes per log line in memory (ASCII-HEX) output. Example: + * + * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo + * |<- w bytes ->| |<- w chars ->| + * + * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details. + */ +void transport_log_set_mem_width(const unsigned w); + +/* Set "output" log level. See TRANSPORT_LOG_LEVEL and + * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels. + */ +void transport_log_set_output_level(const int lvl); + +/* Put mask is a set of flags that define what fields will be added to each + * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be + * used to alter its behavior. See transport_log_set_output_v() for more + * details. + * + * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds + * (NDEBUG is not defined). + */ +enum { + TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */ + TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */ + TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */ + TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */ + TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */ +}; + +typedef struct transport_log_message { + int lvl; /* Log level of the message */ + const char *tag; /* Associated tag (without tag prefix) */ + char *buf; /* Buffer start */ + char *e; /* Buffer end (last position where EOL with 0 could be written) */ + char *p; /* Buffer content end (append position) */ + char *tag_b; /* Prefixed tag start */ + char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */ + char *msg_b; /* Message start (expanded format string) */ +} transport_log_message; + +/* Type of output callback function. It will be called for each log line allowed + * by both "current" and "output" log levels ("enabled" and "turned on"). + * Callback function is allowed to modify content of the buffers pointed by the + * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg + * is UTF-8 encoded (no BOM mark). + */ +typedef void (*transport_log_output_cb)(const transport_log_message *msg, + void *arg); + +/* Format options. For more details see transport_log_set_mem_width(). + */ +typedef struct transport_log_format { + unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */ +} transport_log_format; + +/* Output facility. + */ +typedef struct transport_log_output { + unsigned + mask; /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */ + void *arg; /* User provided output callback argument */ + transport_log_output_cb callback; /* Output callback function */ +} transport_log_output; + +/* Set output callback function. + * + * Mask allows to control what information will be added to the log line buffer + * before callback function is invoked. Default mask value is + * TRANSPORT_LOG_PUT_STD. + */ +void transport_log_set_output_v(const unsigned mask, void *const arg, + const transport_log_output_cb callback); +static _TRANSPORT_LOG_INLINE void transport_log_set_output_p( + const transport_log_output *const output) { + transport_log_set_output_v(output->mask, output->arg, output->callback); +} + +/* Used with _AUX macros and allows to override global format and output + * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for + * values from global configuration. Example: + * + * static const transport_log_output module_output = { + * TRANSPORT_LOG_PUT_STD, 0, custom_output_callback + * }; + * static const transport_log_spec module_spec = { + * TRANSPORT_LOG_GLOBAL_FORMAT, &module_output + * }; + * TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y); + * + * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details. + */ +typedef struct transport_log_spec { + const transport_log_format *format; + const transport_log_output *output; +} transport_log_spec; + +#ifdef __cplusplus +} +#endif + +/* Execute log statement if condition is true. Example: + * + * TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this")); + * TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this")); + * + * Keep in mind though, that if condition can't be evaluated at compile time, + * then it will be evaluated at run time. This will increase exectuable size + * and can have noticeable performance overhead. Try to limit conditions to + * expressions that can be evaluated at compile time. + */ +#define TRANSPORT_LOG_IF(cond, f) \ + do { \ + _TRANSPORT_LOG_IF((cond)) { f; } \ + } \ + _TRANSPORT_LOG_ONCE + +/* Mark log statement as "secret". Log statements that are marked as secrets + * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED). + * Example: + * + * TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card)); + * TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher + * bytes:")); + */ +#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f) + +/* Check "current" log level at compile time (ignoring "output" log level). + * Evaluates to true when specified log level is enabled. For example: + * + * #if TRANSPORT_LOG_ENABLED_DEBUG + * const char *const g_enum_strings[] = { + * "enum_value_0", "enum_value_1", "enum_value_2" + * }; + * #endif + * // ... + * #if TRANSPORT_LOG_ENABLED_DEBUG + * TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]); + * #endif + * + * See TRANSPORT_LOG_LEVEL for details. + */ +#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL) +#define TRANSPORT_LOG_ENABLED_VERBOSE \ + TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE) +#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG) +#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO) +#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN) +#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR) +#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL) + +/* Check "output" log level at run time (taking into account "current" log + * level as well). Evaluates to true when specified log level is turned on AND + * enabled. For example: + * + * if (TRANSPORT_LOG_ON_DEBUG) + * { + * char hash[65]; + * sha256(data_ptr, data_sz, hash); + * TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash); + * } + * + * See TRANSPORT_LOG_OUTPUT_LEVEL for details. + */ +#define TRANSPORT_LOG_ON(lvl) \ + (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL) +#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE) +#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG) +#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO) +#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN) +#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR) +#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL) + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *_transport_log_tag_prefix; +extern transport_log_format _transport_log_global_format; +extern transport_log_output _transport_log_global_output; +extern int _transport_log_global_output_lvl; +extern const transport_log_spec _transport_log_stderr_spec; + +void _transport_log_write_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(6, 7); +void _transport_log_write_aux_d(const char *const func, const char *const file, + const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(7, 8); +void _transport_log_write(const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(3, 4); +void _transport_log_write_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(4, 5); +void _transport_log_write_mem_d(const char *const func, const char *const file, + const unsigned line, const int lvl, + const char *const tag, const void *const d, + const unsigned d_sz, const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(8, 9); +void _transport_log_write_mem_aux_d(const char *const func, + const char *const file, const unsigned line, + const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(9, 10); +void _transport_log_write_mem(const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(5, 6); +void _transport_log_write_mem_aux(const transport_log_spec *const log, + const int lvl, const char *const tag, + const void *const d, const unsigned d_sz, + const char *const fmt, ...) + _TRANSPORT_LOG_PRINTFLIKE(6, 7); + +#ifdef __cplusplus +} +#endif + +/* Message logging macros: + * - TRANSPORT_LOGV("format string", args, ...) + * - TRANSPORT_LOGD("format string", args, ...) + * - TRANSPORT_LOGI("format string", args, ...) + * - TRANSPORT_LOGW("format string", args, ...) + * - TRANSPORT_LOGE("format string", args, ...) + * - TRANSPORT_LOGF("format string", args, ...) + * + * Memory logging macros: + * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...) + * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...) + * + * Auxiliary logging macros: + * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...) + * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...) + * + * Auxiliary memory logging macros: + * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", + * args, ...) + * + * Preformatted string logging macros: + * - TRANSPORT_LOGV_STR("preformatted string"); + * - TRANSPORT_LOGD_STR("preformatted string"); + * - TRANSPORT_LOGI_STR("preformatted string"); + * - TRANSPORT_LOGW_STR("preformatted string"); + * - TRANSPORT_LOGE_STR("preformatted string"); + * - TRANSPORT_LOGF_STR("preformatted string"); + * + * Explicit log level and tag macros: + * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...) + * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", + * args, ...) + * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, + * ...) + * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz, + * "format string", args, ...) + * + * Format string follows printf() conventions. Both data_ptr and data_sz could + * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments + * match format specifiers in format string. + * + * Library assuming UTF-8 encoding for all strings (char *), including format + * string itself. + */ +#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC +#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#else +#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, log, lvl, tag, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \ + do { \ + if (TRANSPORT_LOG_ON(lvl)) \ + _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \ + __LINE__, log, lvl, tag, d, d_sz, \ + __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE +#endif + +static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) { + (void)dummy; +} + +#define _TRANSPORT_LOG_UNUSED(...) \ + do { \ + _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \ + } \ + _TRANSPORT_LOG_ONCE + +#if TRANSPORT_LOG_ENABLED_VERBOSE +#define TRANSPORT_LOGV(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGV_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGV_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_DEBUG +#define TRANSPORT_LOGD(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGD_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGD_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_INFO +#define TRANSPORT_LOGI(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGI_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGI_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_WARN +#define TRANSPORT_LOGW(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGW_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGW_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_ERROR +#define TRANSPORT_LOGE(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGE_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGE_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#if TRANSPORT_LOG_ENABLED_FATAL +#define TRANSPORT_LOGF(...) \ + TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__) +#define TRANSPORT_LOGF_AUX(log, ...) \ + TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \ + __VA_ARGS__) +#define TRANSPORT_LOGF_MEM(d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \ + __VA_ARGS__) +#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...) \ + TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \ + d_sz, __VA_ARGS__) +#else +#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__) +#endif + +#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s)) +#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s)) +#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s)) +#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s)) +#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s)) +#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Output to standard error stream. Library uses it by default, though in few + * cases it could be necessary to specify it explicitly. For example, when + * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT, + * application must define and initialize global output variable: + * + * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR}; + * + * Another example is when using custom output, stderr could be used as a + * fallback when custom output facility failed to initialize: + * + * transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR); + */ +enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD }; +void transport_log_out_stderr_callback(const transport_log_message *const msg, + void *arg); +#define TRANSPORT_LOG_OUT_STDERR \ + TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback + +/* Predefined spec for stderr. Uses global format options + * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to + * force output to stderr for a particular message. Example: + * + * f = fopen("foo.log", "w"); + * if (!f) + * TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file"); + */ +#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/membuf.h b/libtransport/includes/hicn/transport/utils/membuf.h new file mode 100644 index 000000000..9fc37dd25 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/membuf.h @@ -0,0 +1,921 @@ +/* + * Copyright 2013-present Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * The code in this file if adapated from the IOBuf of folly: + * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef _WIN32 +TRANSPORT_GNU_DISABLE_WARNING("-Wshadow") +#endif + +namespace utils { + +class MemBuf { + public: + enum CreateOp { CREATE }; + enum WrapBufferOp { WRAP_BUFFER }; + enum TakeOwnershipOp { TAKE_OWNERSHIP }; + enum CopyBufferOp { COPY_BUFFER }; + + typedef void (*FreeFunction)(void* buf, void* userData); + + static std::unique_ptr create(std::size_t capacity); + MemBuf(CreateOp, std::size_t capacity); + + /** + * Create a new MemBuf, using a single memory allocation to allocate space + * for both the MemBuf object and the data storage space. + * + * This saves one memory allocation. However, it can be wasteful if you + * later need to grow the buffer using reserve(). If the buffer needs to be + * reallocated, the space originally allocated will not be freed() until the + * MemBuf object itself is also freed. (It can also be slightly wasteful in + * some cases where you clone this MemBuf and then free the original MemBuf.) + */ + static std::unique_ptr createCombined(std::size_t capacity); + + /** + * Create a new IOBuf, using separate memory allocations for the IOBuf object + * for the IOBuf and the data storage space. + * + * This requires two memory allocations, but saves space in the long run + * if you know that you will need to reallocate the data buffer later. + */ + static std::unique_ptr createSeparate(std::size_t capacity); + + /** + * Allocate a new MemBuf chain with the requested total capacity, allocating + * no more than maxBufCapacity to each buffer. + */ + static std::unique_ptr createChain(size_t totalCapacity, + std::size_t maxBufCapacity); + + static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true) { + return takeOwnership(buf, capacity, capacity, freeFn, userData, + freeOnError); + } + + MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity, + FreeFunction freeFn = nullptr, void* userData = nullptr, + bool freeOnError = true) + : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {} + + static std::unique_ptr takeOwnership(void* buf, std::size_t capacity, + std::size_t length, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true); + + MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length, + FreeFunction freeFn = nullptr, void* userData = nullptr, + bool freeOnError = true); + + static std::unique_ptr wrapBuffer(const void* buf, + std::size_t capacity); + + static MemBuf wrapBufferAsValue(const void* buf, + std::size_t capacity) noexcept; + + MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept; + + /** + * Convenience function to create a new MemBuf object that copies data from a + * user-supplied buffer, optionally allocating a given amount of + * headroom and tailroom. + */ + static std::unique_ptr copyBuffer(const void* buf, std::size_t size, + std::size_t headroom = 0, + std::size_t minTailroom = 0); + + MemBuf(CopyBufferOp op, const void* buf, std::size_t size, + std::size_t headroom = 0, std::size_t minTailroom = 0); + + /** + * Convenience function to free a chain of MemBufs held by a unique_ptr. + */ + static void destroy(std::unique_ptr&& data) { + auto destroyer = std::move(data); + } + + ~MemBuf(); + + bool empty() const; + + const uint8_t* data() const { return data_; } + + uint8_t* writableData() { return data_; } + + const uint8_t* tail() const { return data_ + length_; } + + uint8_t* writableTail() { return data_ + length_; } + + std::size_t length() const { return length_; } + + std::size_t headroom() const { return std::size_t(data_ - buffer()); } + + std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); } + + const uint8_t* buffer() const { return buf_; } + + uint8_t* writableBuffer() { return buf_; } + + const uint8_t* bufferEnd() const { return buf_ + capacity_; } + + std::size_t capacity() const { return capacity_; } + + MemBuf* next() { return next_; } + + const MemBuf* next() const { return next_; } + + MemBuf* prev() { return prev_; } + + const MemBuf* prev() const { return prev_; } + + /** + * Shift the data forwards in the buffer. + * + * This shifts the data pointer forwards in the buffer to increase the + * headroom. This is commonly used to increase the headroom in a newly + * allocated buffer. + * + * The caller is responsible for ensuring that there is sufficient + * tailroom in the buffer before calling advance(). + * + * If there is a non-zero data length, advance() will use memmove() to shift + * the data forwards in the buffer. In this case, the caller is responsible + * for making sure the buffer is unshared, so it will not affect other MemBufs + * that may be sharing the same underlying buffer. + */ + void advance(std::size_t amount) { + // In debug builds, assert if there is a problem. + assert(amount <= tailroom()); + + if (length_ > 0) { + memmove(data_ + amount, data_, length_); + } + data_ += amount; + } + + /** + * Shift the data backwards in the buffer. + * + * The caller is responsible for ensuring that there is sufficient headroom + * in the buffer before calling retreat(). + * + * If there is a non-zero data length, retreat() will use memmove() to shift + * the data backwards in the buffer. In this case, the caller is responsible + * for making sure the buffer is unshared, so it will not affect other MemBufs + * that may be sharing the same underlying buffer. + */ + void retreat(std::size_t amount) { + // In debug builds, assert if there is a problem. + assert(amount <= headroom()); + + if (length_ > 0) { + memmove(data_ - amount, data_, length_); + } + data_ -= amount; + } + + void prepend(std::size_t amount) { + data_ -= amount; + length_ += amount; + } + + void append(std::size_t amount) { length_ += amount; } + + void trimStart(std::size_t amount) { + data_ += amount; + length_ -= amount; + } + + void trimEnd(std::size_t amount) { length_ -= amount; } + + // Never call clear on cloned membuf sharing different + // portions of the same underlying buffer. + // Use the trim functions instead. + void clear() { + data_ = writableBuffer(); + length_ = 0; + } + + void reserve(std::size_t minHeadroom, std::size_t minTailroom) { + // Maybe we don't need to do anything. + if (headroom() >= minHeadroom && tailroom() >= minTailroom) { + return; + } + // If the buffer is empty but we have enough total room (head + tail), + // move the data_ pointer around. + if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) { + data_ = writableBuffer() + minHeadroom; + return; + } + // Bah, we have to do actual work. + reserveSlow(minHeadroom, minTailroom); + } + + bool isChained() const { + assert((next_ == this) == (prev_ == this)); + return next_ != this; + } + + size_t countChainElements() const; + + std::size_t computeChainDataLength() const; + + void prependChain(std::unique_ptr&& iobuf); + + void appendChain(std::unique_ptr&& iobuf) { + // Just use prependChain() on the next element in our chain + next_->prependChain(std::move(iobuf)); + } + + std::unique_ptr unlink() { + next_->prev_ = prev_; + prev_->next_ = next_; + prev_ = this; + next_ = this; + return std::unique_ptr(this); + } + + /** + * Remove this MemBuf from its current chain and return a unique_ptr to + * the MemBuf that formerly followed it in the chain. + */ + std::unique_ptr pop() { + MemBuf* next = next_; + next_->prev_ = prev_; + prev_->next_ = next_; + prev_ = this; + next_ = this; + return std::unique_ptr((next == this) ? nullptr : next); + } + + /** + * Remove a subchain from this chain. + * + * Remove the subchain starting at head and ending at tail from this chain. + * + * Returns a unique_ptr pointing to head. (In other words, ownership of the + * head of the subchain is transferred to the caller.) If the caller ignores + * the return value and lets the unique_ptr be destroyed, the subchain will + * be immediately destroyed. + * + * The subchain referenced by the specified head and tail must be part of the + * same chain as the current MemBuf, but must not contain the current MemBuf. + * However, the specified head and tail may be equal to each other (i.e., + * they may be a subchain of length 1). + */ + std::unique_ptr separateChain(MemBuf* head, MemBuf* tail) { + assert(head != this); + assert(tail != this); + + head->prev_->next_ = tail->next_; + tail->next_->prev_ = head->prev_; + + head->prev_ = tail; + tail->next_ = head; + + return std::unique_ptr(head); + } + + /** + * Return true if at least one of the MemBufs in this chain are shared, + * or false if all of the MemBufs point to unique buffers. + * + * Use isSharedOne() to only check this MemBuf rather than the entire chain. + */ + bool isShared() const { + const MemBuf* current = this; + while (true) { + if (current->isSharedOne()) { + return true; + } + current = current->next_; + if (current == this) { + return false; + } + } + } + + /** + * Return true if all MemBufs in this chain are managed by the usual + * refcounting mechanism (and so the lifetime of the underlying memory + * can be extended by clone()). + */ + bool isManaged() const { + const MemBuf* current = this; + while (true) { + if (!current->isManagedOne()) { + return false; + } + current = current->next_; + if (current == this) { + return true; + } + } + } + + /** + * Return true if this MemBuf is managed by the usual refcounting mechanism + * (and so the lifetime of the underlying memory can be extended by + * cloneOne()). + */ + bool isManagedOne() const { return sharedInfo(); } + + /** + * Return true if other MemBufs are also pointing to the buffer used by this + * MemBuf, and false otherwise. + * + * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the + * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned + * from such an MemBuf), it is always considered shared. + * + * This only checks the current MemBuf, and not other MemBufs in the chain. + */ + bool isSharedOne() const { + // If this is a user-owned buffer, it is always considered shared + if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) { + return true; + } + + if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) { + return true; + } + + if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) { + return false; + } + + // flag_maybe_shared is set, so we need to check the reference count. + // (Checking the reference count requires an atomic operation, which is why + // we prefer to only check flag_maybe_shared if possible.) + bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1; + if (!shared) { + // we're the last one left + clearFlags(flag_maybe_shared); + } + return shared; + } + + /** + * Ensure that this MemBuf has a unique buffer that is not shared by other + * MemBufs. + * + * unshare() operates on an entire chain of MemBuf objects. If the chain is + * shared, it may also coalesce the chain when making it unique. If the + * chain is coalesced, subsequent MemBuf objects in the current chain will be + * automatically deleted. + * + * Note that buffers owned by other (non-MemBuf) users are automatically + * considered shared. + * + * Throws std::bad_alloc on error. On error the MemBuf chain will be + * unmodified. + * + * Currently unshare may also throw std::overflow_error if it tries to + * coalesce. (TODO: In the future it would be nice if unshare() were smart + * enough not to coalesce the entire buffer if the data is too large. + * However, in practice this seems unlikely to become an issue.) + */ + void unshare() { + if (isChained()) { + unshareChained(); + } else { + unshareOne(); + } + } + + /** + * Ensure that this MemBuf has a unique buffer that is not shared by other + * MemBufs. + * + * unshareOne() operates on a single MemBuf object. This MemBuf will have a + * unique buffer after unshareOne() returns, but other MemBufs in the chain + * may still be shared after unshareOne() returns. + * + * Throws std::bad_alloc on error. On error the MemBuf will be unmodified. + */ + void unshareOne() { + if (isSharedOne()) { + unshareOneSlow(); + } + } + + /** + * Mark the underlying buffers in this chain as shared with external memory + * management mechanism. This will make isShared() always returns true. + * + * This function is not thread-safe, and only safe to call immediately after + * creating an MemBuf, before it has been shared with other threads. + */ + void markExternallyShared(); + + /** + * Mark the underlying buffer that this MemBuf refers to as shared with + * external memory management mechanism. This will make isSharedOne() always + * returns true. + * + * This function is not thread-safe, and only safe to call immediately after + * creating an MemBuf, before it has been shared with other threads. + */ + void markExternallySharedOne() { + SharedInfo* info = sharedInfo(); + if (info) { + info->externallyShared = true; + } + } + + /** + * Ensure that the memory that MemBufs in this chain refer to will continue to + * be allocated for as long as the MemBufs of the chain (or any clone()s + * created from this point onwards) is alive. + * + * This only has an effect for user-owned buffers (created with the + * WRAP_BUFFER constructor or wrapBuffer factory function), in which case + * those buffers are unshared. + */ + void makeManaged() { + if (isChained()) { + makeManagedChained(); + } else { + makeManagedOne(); + } + } + + /** + * Ensure that the memory that this MemBuf refers to will continue to be + * allocated for as long as this MemBuf (or any clone()s created from this + * point onwards) is alive. + * + * This only has an effect for user-owned buffers (created with the + * WRAP_BUFFER constructor or wrapBuffer factory function), in which case + * those buffers are unshared. + */ + void makeManagedOne() { + if (!isManagedOne()) { + // We can call the internal function directly; unmanaged implies shared. + unshareOneSlow(); + } + } + + // /** + // * Coalesce this MemBuf chain into a single buffer. + // * + // * This method moves all of the data in this MemBuf chain into a single + // * contiguous buffer, if it is not already in one buffer. After coalesce() + // * returns, this MemBuf will be a chain of length one. Other MemBufs in + // the + // * chain will be automatically deleted. + // * + // * After coalescing, the MemBuf will have at least as much headroom as the + // * first MemBuf in the chain, and at least as much tailroom as the last + // MemBuf + // * in the chain. + // * + // * Throws std::bad_alloc on error. On error the MemBuf chain will be + // * unmodified. + // * + // * Returns ByteRange that points to the data MemBuf stores. + // */ + // ByteRange coalesce() { + // const std::size_t newHeadroom = headroom(); + // const std::size_t newTailroom = prev()->tailroom(); + // return coalesceWithHeadroomTailroom(newHeadroom, newTailroom); + // } + + // /** + // * This is similar to the coalesce() method, except this allows to set a + // * headroom and tailroom after coalescing. + // * + // * Returns ByteRange that points to the data MemBuf stores. + // */ + // ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom, + // std::size_t newTailroom) { + // if (isChained()) { + // coalesceAndReallocate(newHeadroom, computeChainDataLength(), this, + // newTailroom); + // } + // return ByteRange(data_, length_); + // } + + /** + * Ensure that this chain has at least maxLength bytes available as a + * contiguous memory range. + * + * This method coalesces whole buffers in the chain into this buffer as + * necessary until this buffer's length() is at least maxLength. + * + * After coalescing, the MemBuf will have at least as much headroom as the + * first MemBuf in the chain, and at least as much tailroom as the last MemBuf + * that was coalesced. + * + * Throws std::bad_alloc or std::overflow_error on error. On error the MemBuf + * chain will be unmodified. Throws std::overflow_error if maxLength is + * longer than the total chain length. + * + * Upon return, either enough of the chain was coalesced into a contiguous + * region, or the entire chain was coalesced. That is, + * length() >= maxLength || !isChained() is true. + */ + void gather(std::size_t maxLength) { + if (!isChained() || length_ >= maxLength) { + return; + } + coalesceSlow(maxLength); + } + + /** + * Return a new MemBuf chain sharing the same data as this chain. + * + * The new MemBuf chain will normally point to the same underlying data + * buffers as the original chain. (The one exception to this is if some of + * the MemBufs in this chain contain small internal data buffers which cannot + * be shared.) + */ + std::unique_ptr clone() const; + + /** + * Similar to clone(). But returns MemBuf by value rather than heap-allocating + * it. + */ + MemBuf cloneAsValue() const; + + /** + * Return a new MemBuf with the same data as this MemBuf. + * + * The new MemBuf returned will not be part of a chain (even if this MemBuf is + * part of a larger chain). + */ + std::unique_ptr cloneOne() const; + + /** + * Similar to cloneOne(). But returns MemBuf by value rather than + * heap-allocating it. + */ + MemBuf cloneOneAsValue() const; + + /** + * Return a new unchained MemBuf that may share the same data as this chain. + * + * If the MemBuf chain is not chained then the new MemBuf will point to the + * same underlying data buffer as the original chain. Otherwise, it will clone + * and coalesce the MemBuf chain. + * + * The new MemBuf will have at least as much headroom as the first MemBuf in + * the chain, and at least as much tailroom as the last MemBuf in the chain. + * + * Throws std::bad_alloc on error. + */ + std::unique_ptr cloneCoalesced() const; + + /** + * This is similar to the cloneCoalesced() method, except this allows to set a + * headroom and tailroom for the new MemBuf. + */ + std::unique_ptr cloneCoalescedWithHeadroomTailroom( + std::size_t newHeadroom, std::size_t newTailroom) const; + + /** + * Similar to cloneCoalesced(). But returns MemBuf by value rather than + * heap-allocating it. + */ + MemBuf cloneCoalescedAsValue() const; + + /** + * This is similar to the cloneCoalescedAsValue() method, except this allows + * to set a headroom and tailroom for the new MemBuf. + */ + MemBuf cloneCoalescedAsValueWithHeadroomTailroom( + std::size_t newHeadroom, std::size_t newTailroom) const; + + /** + * Similar to Clone(). But use other as the head node. Other nodes in the + * chain (if any) will be allocted on heap. + */ + void cloneInto(MemBuf& other) const { other = cloneAsValue(); } + + /** + * Similar to CloneOne(). But to fill an existing MemBuf instead of a new + * MemBuf. + */ + void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); } + + /** + * Return an iovector suitable for e.g. writev() + * + * auto iov = buf->getIov(); + * auto xfer = writev(fd, iov.data(), iov.size()); + * + * Naturally, the returned iovector is invalid if you modify the buffer + * chain. + */ + std::vector getIov() const; + + /** + * Update an existing iovec array with the MemBuf data. + * + * New iovecs will be appended to the existing vector; anything already + * present in the vector will be left unchanged. + * + * Naturally, the returned iovec data will be invalid if you modify the + * buffer chain. + */ + void appendToIov(std::vector* iov) const; + + /** + * Fill an iovec array with the MemBuf data. + * + * Returns the number of iovec filled. If there are more buffer than + * iovec, returns 0. This version is suitable to use with stack iovec + * arrays. + * + * Naturally, the filled iovec data will be invalid if you modify the + * buffer chain. + */ + size_t fillIov(struct iovec* iov, size_t len) const; + + /** + * A helper that wraps a number of iovecs into an MemBuf chain. If count == + * 0, then a zero length buf is returned. This function never returns + * nullptr. + */ + static std::unique_ptr wrapIov(const iovec* vec, size_t count); + + /** + * A helper that takes ownerships a number of iovecs into an MemBuf chain. If + * count == 0, then a zero length buf is returned. This function never + * returns nullptr. + */ + static std::unique_ptr takeOwnershipIov(const iovec* vec, + size_t count, + FreeFunction freeFn = nullptr, + void* userData = nullptr, + bool freeOnError = true); + + /* + * Overridden operator new and delete. + * These perform specialized memory management to help support + * createCombined(), which allocates MemBuf objects together with the buffer + * data. + */ + void* operator new(size_t size); + void* operator new(size_t size, void* ptr); + void operator delete(void* ptr); + void operator delete(void* ptr, void* placement); + + // /** + // * Iteration support: a chain of MemBufs may be iterated through using + // * STL-style iterators over const ByteRanges. Iterators are only + // invalidated + // * if the MemBuf that they currently point to is removed. + // */ + // Iterator cbegin() const; + // Iterator cend() const; + // Iterator begin() const; + // Iterator end() const; + + /** + * Allocate a new null buffer. + * + * This can be used to allocate an empty MemBuf on the stack. It will have no + * space allocated for it. This is generally useful only to later use move + * assignment to fill out the MemBuf. + */ + MemBuf() noexcept; + + /** + * Move constructor and assignment operator. + * + * In general, you should only ever move the head of an MemBuf chain. + * Internal nodes in an MemBuf chain are owned by the head of the chain, and + * should not be moved from. (Technically, nothing prevents you from moving + * a non-head node, but the moved-to node will replace the moved-from node in + * the chain. This has implications for ownership, since non-head nodes are + * owned by the chain head. You are then responsible for relinquishing + * ownership of the moved-to node, and manually deleting the moved-from + * node.) + * + * With the move assignment operator, the destination of the move should be + * the head of an MemBuf chain or a solitary MemBuf not part of a chain. If + * the move destination is part of a chain, all other MemBufs in the chain + * will be deleted. + */ + MemBuf(MemBuf&& other) noexcept; + MemBuf& operator=(MemBuf&& other) noexcept; + + MemBuf(const MemBuf& other); + MemBuf& operator=(const MemBuf& other); + + private: + enum FlagsEnum : uintptr_t { + // Adding any more flags would not work on 32-bit architectures, + // as these flags are stashed in the least significant 2 bits of a + // max-align-aligned pointer. + flag_free_shared_info = 0x1, + flag_maybe_shared = 0x2, + flag_mask = flag_free_shared_info | flag_maybe_shared + }; + + struct SharedInfo { + SharedInfo(); + SharedInfo(FreeFunction fn, void* arg); + + // A pointer to a function to call to free the buffer when the refcount + // hits 0. If this is null, free() will be used instead. + FreeFunction freeFn; + void* userData; + std::atomic refcount; + bool externallyShared{false}; + }; + // Helper structs for use by operator new and delete + struct HeapPrefix; + struct HeapStorage; + struct HeapFullStorage; + + /** + * Create a new MemBuf pointing to an external buffer. + * + * The caller is responsible for holding a reference count for this new + * MemBuf. The MemBuf constructor does not automatically increment the + * reference count. + */ + struct InternalConstructor {}; // avoid conflicts + MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf, + std::size_t capacity, uint8_t* data, std::size_t length) noexcept; + + void unshareOneSlow(); + void unshareChained(); + void makeManagedChained(); + void coalesceSlow(); + void coalesceSlow(size_t maxLength); + // newLength must be the entire length of the buffers between this and + // end (no truncation) + void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end, + size_t newTailroom); + void coalesceAndReallocate(size_t newLength, MemBuf* end) { + coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom()); + } + void decrementRefcount(); + void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom); + void freeExtBuffer(); + + static size_t goodExtBufferSize(std::size_t minCapacity); + static void initExtBuffer(uint8_t* buf, size_t mallocSize, + SharedInfo** infoReturn, + std::size_t* capacityReturn); + static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn, + SharedInfo** infoReturn, + std::size_t* capacityReturn); + static void releaseStorage(HeapStorage* storage, uint16_t freeFlags); + static void freeInternalBuf(void* buf, void* userData); + + /* + * Member variables + */ + + /* + * Links to the next and the previous MemBuf in this chain. + * + * The chain is circularly linked (the last element in the chain points back + * at the head), and next_ and prev_ can never be null. If this MemBuf is the + * only element in the chain, next_ and prev_ will both point to this. + */ + MemBuf* next_{this}; + MemBuf* prev_{this}; + + /* + * A pointer to the start of the data referenced by this MemBuf, and the + * length of the data. + * + * This may refer to any subsection of the actual buffer capacity. + */ + uint8_t* data_{nullptr}; + uint8_t* buf_{nullptr}; + std::size_t length_{0}; + std::size_t capacity_{0}; + + // Pack flags in least significant 2 bits, sharedInfo in the rest + mutable uintptr_t flags_and_shared_info_{0}; + + static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags, + SharedInfo* info) { + uintptr_t uinfo = reinterpret_cast(info); + return flags | uinfo; + } + + inline SharedInfo* sharedInfo() const { + return reinterpret_cast(flags_and_shared_info_ & ~flag_mask); + } + + inline void setSharedInfo(SharedInfo* info) { + uintptr_t uinfo = reinterpret_cast(info); + flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo; + } + + inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; } + + // flags_ are changed from const methods + inline void setFlags(uintptr_t flags) const { + flags_and_shared_info_ |= flags; + } + + inline void clearFlags(uintptr_t flags) const { + flags_and_shared_info_ &= ~flags; + } + + inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) { + flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info); + } + + struct DeleterBase { + virtual ~DeleterBase() {} + virtual void dispose(void* p) = 0; + }; + + template + struct UniquePtrDeleter : public DeleterBase { + typedef typename UniquePtr::pointer Pointer; + typedef typename UniquePtr::deleter_type Deleter; + + explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {} + void dispose(void* p) override { + try { + deleter_(static_cast(p)); + delete this; + } catch (...) { + abort(); + } + } + + private: + Deleter deleter_; + }; + + static void freeUniquePtrBuffer(void* ptr, void* userData) { + static_cast(userData)->dispose(ptr); + } +}; + +// template +// typename std::enable_if< +// detail::IsUniquePtrToSL::value, +// std::unique_ptr>::type +// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) { +// size_t size = count * sizeof(typename UniquePtr::element_type); +// auto deleter = new UniquePtrDeleter(buf.get_deleter()); +// return takeOwnership( +// buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter); +// } + +inline std::unique_ptr MemBuf::copyBuffer(const void* data, + std::size_t size, + std::size_t headroom, + std::size_t minTailroom) { + std::size_t capacity = headroom + size + minTailroom; + std::unique_ptr buf = MemBuf::create(capacity); + buf->advance(headroom); + if (size != 0) { + memcpy(buf->writableData(), data, size); + } + buf->append(size); + return buf; +} + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/object_pool.h b/libtransport/includes/hicn/transport/utils/object_pool.h new file mode 100644 index 000000000..f78bd2aa2 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/object_pool.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// TODO +#include +#include + +#include +#include +#include + +namespace utils { + +template +class ObjectPool { + class ObjectDeleter { + public: + ObjectDeleter(ObjectPool *pool = nullptr) : pool_(pool) {} + + void operator()(T *t) { + if (pool_) { + pool_->add(t); + } else { + delete t; + } + } + + private: + ObjectPool *pool_; + }; + + public: + using Ptr = std::unique_ptr; + + ObjectPool() : destructor_(false) {} + + ~ObjectPool() { + destructor_ = true; + for (auto &ptr : object_pool_) { + ptr.reset(); + } + } + + std::pair get() { + if (object_pool_.empty()) { + return std::make_pair(false, makePtr(nullptr)); + } + + utils::SpinLock::Acquire locked(object_pool_lock_); + auto ret = std::move(object_pool_.front()); + object_pool_.pop_front(); + return std::make_pair(true, std::move(ret)); + } + + void add(T *object) { + utils::SpinLock::Acquire locked(object_pool_lock_); + + if (TRANSPORT_EXPECT_TRUE(!destructor_)) { + object_pool_.emplace_back(makePtr(object)); + } else { + delete object; + } + } + + Ptr makePtr(T *object) { return Ptr(object, ObjectDeleter(this)); } + + private: + // No copies + ObjectPool(const ObjectPool &other) = delete; + + utils::SpinLock object_pool_lock_; + std::deque object_pool_; + bool destructor_; +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/ring_buffer.h b/libtransport/includes/hicn/transport/utils/ring_buffer.h new file mode 100644 index 000000000..9babe56bd --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/ring_buffer.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace utils { + +/** + * NOTE: Single consumer single producer ring buffer + */ +template +class CircularFifo { + public: + enum { Capacity = Size + 1 }; + + CircularFifo() : tail_(0), head_(0), size_(0) {} + virtual ~CircularFifo() {} + + bool push(const Element& item); + bool push(Element&& item); + bool pop(Element& item); + + bool wasEmpty() const; + bool wasFull() const; + bool isLockFree() const; + std::size_t size() const; + + private: + std::size_t increment(std::size_t idx) const; + std::atomic tail_; // tail(input) index + Element array_[Capacity]; + std::atomic head_; // head(output) index + std::atomic size_; +}; + +template +bool CircularFifo::push(const Element& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = item; + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +/** + * Push by move + */ +template +bool CircularFifo::push(Element&& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = std::move(item); + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +// Pop by Consumer can only update the head +// (load with relaxed, store with release) +// the tail must be accessed with at least acquire +template +bool CircularFifo::pop(Element& item) { + const size_t current_head = head_.load(std::memory_order_relaxed); + if (current_head == tail_.load(std::memory_order_acquire)) { + return false; // empty queue + } + + item = std::move(array_[current_head]); + head_.store(increment(current_head), std::memory_order_release); + size_--; + return true; +} + +template +bool CircularFifo::wasEmpty() const { + // snapshot with acceptance of that this comparison operation is not atomic + return (head_.load() == tail_.load()); +} + +// snapshot with acceptance that this comparison is not atomic +template +bool CircularFifo::wasFull() const { + const auto next_tail = + increment(tail_.load()); // acquire, we dont know who call + return (next_tail == head_.load()); +} + +template +bool CircularFifo::isLockFree() const { + return (tail_.is_lock_free() && head_.is_lock_free()); +} + +template +std::size_t CircularFifo::increment(std::size_t idx) const { + return (idx + 1) % Capacity; +} + +template +std::size_t CircularFifo::size() const { + return size_.load(std::memory_order_relaxed); +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/spinlock.h b/libtransport/includes/hicn/transport/utils/spinlock.h new file mode 100644 index 000000000..009a94454 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/spinlock.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace utils { + +class SpinLock : private std::atomic_flag { + public: + class Acquire { + public: + Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); } + + ~Acquire() { spin_lock_.unlock(); } + + // No copies + Acquire& operator=(const Acquire&) = delete; + Acquire(const Acquire&) = delete; + + private: + SpinLock& spin_lock_; + }; + + SpinLock() { clear(); } + + void lock() { + // busy-wait + while (std::atomic_flag::test_and_set(std::memory_order_acquire)) + ; + } + + void unlock() { clear(std::memory_order_release); } + + bool tryLock() { + return std::atomic_flag::test_and_set(std::memory_order_acquire); + } +}; + +} // namespace utils \ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/string_tokenizer.h b/libtransport/includes/hicn/transport/utils/string_tokenizer.h new file mode 100644 index 000000000..36630eb58 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/string_tokenizer.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace utils { + +class StringTokenizer { + public: + StringTokenizer(const std::string &str); + StringTokenizer(const std::string &str, const std::string &delim); + + bool hasMoreTokens(); + std::string nextToken(); + + private: + std::string str_; + std::string delimiter_; +}; + +} // namespace utils diff --git a/libtransport/includes/hicn/transport/utils/uri.h b/libtransport/includes/hicn/transport/utils/uri.h new file mode 100644 index 000000000..7c28e8552 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/uri.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include // find +#include + +namespace utils { + +class Uri { + typedef std::string::const_iterator iterator_t; + + public: + Uri(); + + Uri &parse(const std::string &uri); + + Uri &parseProtocolAndLocator(const std::string &locator); + + std::string getQueryString(); + + std::string getPath(); + + std::string getProtocol(); + + std::string getLocator(); + + std::string getPort(); + + private: + std::string query_string_, path_, protocol_, locator_, port_; +}; // uri + +} // namespace utils -- cgit 1.2.3-korg