aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/includes/hicn/transport/utils
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/includes/hicn/transport/utils')
-rw-r--r--libtransport/includes/hicn/transport/utils/CMakeLists.txt39
-rw-r--r--libtransport/includes/hicn/transport/utils/array.h62
-rw-r--r--libtransport/includes/hicn/transport/utils/branch_prediction.h27
-rw-r--r--libtransport/includes/hicn/transport/utils/chrono_typedefs.h27
-rw-r--r--libtransport/includes/hicn/transport/utils/conversions.h37
-rw-r--r--libtransport/includes/hicn/transport/utils/daemonizator.h30
-rw-r--r--libtransport/includes/hicn/transport/utils/hash.h101
-rw-r--r--libtransport/includes/hicn/transport/utils/linux.h64
-rw-r--r--libtransport/includes/hicn/transport/utils/literals.h55
-rw-r--r--libtransport/includes/hicn/transport/utils/log.h1057
-rw-r--r--libtransport/includes/hicn/transport/utils/membuf.h921
-rw-r--r--libtransport/includes/hicn/transport/utils/object_pool.h90
-rw-r--r--libtransport/includes/hicn/transport/utils/ring_buffer.h129
-rw-r--r--libtransport/includes/hicn/transport/utils/spinlock.h53
-rw-r--r--libtransport/includes/hicn/transport/utils/string_tokenizer.h35
-rw-r--r--libtransport/includes/hicn/transport/utils/uri.h47
16 files changed, 2774 insertions, 0 deletions
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 <hicn/transport/portability/portability.h>
+
+#include <cstddef>
+
+namespace utils {
+
+template <typename T = uint8_t>
+class Array {
+ public:
+ explicit Array(const T *array, size_t size) : array_(array), size_(size) {
+ this->array_ = array;
+ this->size_ = size;
+ }
+
+ Array() : array_(nullptr), size_(0) {
+ this->array_ = nullptr;
+ this->size_ = 0;
+ }
+
+ TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; }
+
+ TRANSPORT_ALWAYS_INLINE T *writableData() const {
+ return const_cast<T *>(array_);
+ }
+
+ TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; }
+
+ TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) {
+ array_ = data;
+ return *this;
+ }
+
+ TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) {
+ size_ = size;
+ return *this;
+ }
+
+ TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; }
+
+ private:
+ const T *array_;
+ std::size_t size_;
+};
+
+} // namespace utils
diff --git a/libtransport/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 <chrono>
+
+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 <hicn/transport/portability/portability.h>
+
+#include <stdio.h>
+#include <cstdint>
+#include <string>
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress(
+ const std::string& mac_address, uint8_t* mac_byte_array) {
+ const char* mac = mac_address.c_str();
+
+ sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0],
+ &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3],
+ &mac_byte_array[4], &mac_byte_array[5]);
+
+ return 0;
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/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 <cstdlib>
+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 <hicn/transport/portability/portability.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace utils {
+
+namespace hash {
+
+/*
+ * Fowler / Noll / Vo (FNV) Hash
+ * http://www.isthe.com/chongo/tech/comp/fnv/
+ */
+
+const uint32_t FNV_32_HASH_START = 2166136261UL;
+const uint64_t FNV_64_HASH_START = 14695981039346656037ULL;
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s,
+ uint32_t hash = FNV_32_HASH_START) {
+ for (; *s; ++s) {
+ hash +=
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+ hash ^= *s;
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n,
+ uint32_t hash = FNV_32_HASH_START) {
+ // forcing signed char, since other platforms can use unsigned
+ const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+ for (size_t i = 0; i < n; ++i) {
+ hash +=
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+ hash ^= char_buf[i];
+ }
+
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str,
+ uint32_t hash = FNV_32_HASH_START) {
+ return fnv32_buf(str.data(), str.size(), hash);
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s,
+ uint64_t hash = FNV_64_HASH_START) {
+ for (; *s; ++s) {
+ hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+ (hash << 8) + (hash << 40);
+ hash ^= *s;
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n,
+ uint64_t hash = FNV_64_HASH_START) {
+ // forcing signed char, since other platforms can use unsigned
+ const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+ for (size_t i = 0; i < n; ++i) {
+ hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+ (hash << 8) + (hash << 40);
+ hash ^= char_buf[i];
+ }
+ return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str,
+ uint64_t hash = FNV_64_HASH_START) {
+ return fnv64_buf(str.data(), str.size(), hash);
+}
+
+} // namespace hash
+
+} // namespace utils
diff --git a/libtransport/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 <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <string>
+
+#define LINK_LOCAL_PREFIX 0xfe80
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress(
+ const std::string &interface_name, struct sockaddr_in6 *address) {
+ struct ifaddrs *ifap, *ifa;
+ char addr[INET6_ADDRSTRLEN];
+
+ getifaddrs(&ifap);
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ strcmp(ifa->ifa_name, interface_name.c_str()) == 0) {
+ struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr;
+ uint16_t prefix = 0;
+ memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t));
+
+ if (htons(LINK_LOCAL_PREFIX) != prefix) {
+ *address = *(struct sockaddr_in6 *)ifa->ifa_addr;
+ getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
+ sizeof(addr), NULL, 0, NI_NUMERICHOST);
+ TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr);
+ }
+ }
+ }
+
+ freeifaddrs(ifap);
+
+ return 0;
+}
+
+} // namespace utils
+
+#endif // __linux__ \ No newline at end of file
diff --git a/libtransport/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 <hicn/transport/portability/portability.h>
+
+#include <cstdint>
+
+TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) {
+ return static_cast<std::uint8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16(
+ unsigned long long value) {
+ return static_cast<std::uint16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32(
+ unsigned long long value) {
+ return static_cast<std::uint32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64(
+ unsigned long long value) {
+ return static_cast<std::uint64_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) {
+ return static_cast<std::int8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) {
+ return static_cast<std::int16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) {
+ return static_cast<std::int32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) {
+ return static_cast<std::int64_t>(value);
+} \ No newline at end of file
diff --git a/libtransport/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 <hicn/transport_log.h>
+ *
+ * Compilation will fail when included file has different version.
+ */
+#define TRANSPORT_LOG_VERSION 4
+#if defined(TRANSPORT_LOG_VERSION_REQUIRED)
+#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION
+#error different transport_log version required
+#endif
+#endif
+
+/* Log level guideline:
+ * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely
+ * unexpected. Process can't continue and must be terminated. Example: division
+ * by zero, unexpected modifications from other thread.
+ * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected.
+ * The process is able to recover and continue execution. Example: out of memory
+ * (could also be FATAL if not handled properly).
+ * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen
+ * and significantly changes application behavior for some period of time.
+ * Example: configuration file not found, auth error.
+ * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state
+ * transition.
+ * Example: app started, user logged in.
+ * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct
+ * the execution path. Usually disabled in release builds.
+ * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release
+ * builds.
+ *
+ * *Ideally*, log file of debugged, well tested, production ready application
+ * should be empty or very small. Choosing a right log level is as important as
+ * providing short and self descriptive log message.
+ */
+#define TRANSPORT_LOG_VERBOSE 1
+#define TRANSPORT_LOG_DEBUG 2
+#define TRANSPORT_LOG_INFO 3
+#define TRANSPORT_LOG_WARN 4
+#define TRANSPORT_LOG_ERROR 5
+#define TRANSPORT_LOG_FATAL 6
+#define TRANSPORT_LOG_NONE 0xFF
+
+/* "Current" log level is a compile time check and has no runtime overhead. Log
+ * level that is below current log level it said to be "disabled". Otherwise,
+ * it's "enabled". Log messages that are disabled has no runtime overhead - they
+ * are converted to no-op by preprocessor and then eliminated by compiler.
+ * Current log level is configured per compilation module (.c/.cpp/.m file) by
+ * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL
+ * has higer priority and when defined overrides value provided by
+ * TRANSPORT_LOG_DEF_LEVEL.
+ *
+ * Common practice is to define default current log level with
+ * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp,
+ * etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO
+ *
+ * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then
+ * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and
+ * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL
+#elif defined(TRANSPORT_LOG_DEF_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO
+#else
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG
+#endif
+#endif
+
+/* "Output" log level is a runtime check. When log level is below output log
+ * level it said to be "turned off" (or just "off" for short). Otherwise it's
+ * "turned on" (or just "on"). Log levels that were "disabled" (see
+ * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but
+ * "enabled" log levels could be "turned off". Only messages with log level
+ * which is "turned on" will reach output facility. All other messages will be
+ * ignored (and their arguments will not be evaluated). Output log level is a
+ * global property and configured per process using
+ * transport_log_set_output_level() function which can be called at any time.
+ *
+ * Though in some cases it could be useful to configure output log level per
+ * compilation module or per library. There are two ways to achieve that:
+ * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired
+ * output log level.
+ * - Copy transport_log.h and transport_log.c files into your library and build
+ * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See
+ * TRANSPORT_LOG_LIBRARY_PREFIX for more details.
+ *
+ * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that
+ * corresponds to desired output log level. Use it only when compilation module
+ * is required to have output log level which is different from global output
+ * log level set by transport_log_set_output_level() function. For other cases,
+ * consider defining TRANSPORT_LOG_LEVEL or using
+ * transport_log_set_output_level() function.
+ *
+ * Example:
+ *
+ * #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level
+ * #include <hicn/transport_log.h>
+ * static int g_module_log_level = TRANSPORT_LOG_INFO;
+ * static void foo() {
+ * TRANSPORT_LOGI("Will check g_module_log_level for output log level");
+ * }
+ * void debug_log(bool on) {
+ * g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO;
+ * }
+ *
+ * Note on performance. This expression will be evaluated each time message is
+ * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL
+ * for details). Keep this expression as simple as possible, otherwise it will
+ * not only add runtime overhead, but also will increase size of call site
+ * (which will result in larger executable). The prefered way is to use integer
+ * variable (as in example above). If structure must be used, log_level field
+ * must be the first field in this structure:
+ *
+ * #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level)
+ * #include <hicn/transport_log.h>
+ * struct config {
+ * int log_level;
+ * unsigned other_field;
+ * [...]
+ * };
+ * static config g_config = {TRANSPORT_LOG_INFO, 0, ...};
+ *
+ * This allows compiler to generate more compact load instruction (no need to
+ * specify offset since it's zero). Calling a function to get output log level
+ * is generaly a bad idea, since it will increase call site size and runtime
+ * overhead even further.
+ */
+#if defined(TRANSPORT_LOG_OUTPUT_LEVEL)
+#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL
+#else
+#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl
+#endif
+
+/* "Tag" is a compound string that could be associated with a log message. It
+ * consists of tag prefix and tag (both are optional).
+ *
+ * Tag prefix is a global property and configured per process using
+ * transport_log_set_tag_prefix() function. Tag prefix identifies context in
+ * which component or module is running (e.g. process name). For example, the
+ * same library could be used in both client and server processes that work on
+ * the same machine. Tag prefix could be used to easily distinguish between
+ * them. For more details about tag prefix see transport_log_set_tag_prefix()
+ * function. Tag prefix
+ *
+ * Tag identifies component or module. It is configured per compilation module
+ * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG.
+ * TRANSPORT_LOG_TAG has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to
+ * (const char *), so for strings double quotes must be used.
+ *
+ * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g.
+ * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\"
+ *
+ * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_TAG "MAIN"
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will
+ * be added to the log message (tag prefix still could be added though).
+ *
+ * Output example:
+ *
+ * 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1
+ * | |
+ * | +- tag (e.g. module)
+ * +- tag prefix (e.g. process name)
+ */
+#if defined(TRANSPORT_LOG_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG
+#elif defined(TRANSPORT_LOG_DEF_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG
+#else
+#define _TRANSPORT_LOG_TAG 0
+#endif
+
+/* Source location is part of a log line that describes location (function or
+ * method name, file name and line number, e.g. "runloop@main.cpp:68") of a
+ * log statement that produced it.
+ * Source location formats are:
+ * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line.
+ * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and
+ * line number, e.g. "@main.cpp:68").
+ * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or
+ * method name, file and line number, e.g. "runloop@main.cpp:68").
+ */
+#define TRANSPORT_LOG_SRCLOC_NONE 0
+#define TRANSPORT_LOG_SRCLOC_SHORT 1
+#define TRANSPORT_LOG_SRCLOC_LONG 2
+
+/* Source location format is configured per compilation module (.c/.cpp/.m
+ * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC.
+ * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_SRCLOC.
+ *
+ * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in
+ * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG
+ *
+ * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ * #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then
+ * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined)
+ * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC
+#elif defined(TRANSPORT_LOG_DEF_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+#else
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG
+#endif
+#endif
+#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION
+#else
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0
+#endif
+
+/* Censoring provides conditional logging of secret information, also known as
+ * Personally Identifiable Information (PII) or Sensitive Personal Information
+ * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled
+ * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked
+ * as "secrets" will be ignored and will have zero overhead (arguments also will
+ * not be evaluated).
+ */
+#define TRANSPORT_LOG_CENSORED 1
+#define TRANSPORT_LOG_UNCENSORED 0
+
+/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
+ * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING.
+ * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_CENSORING.
+ *
+ * Common practice is to define default censoring with
+ * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt,
+ * gyp, etc.) for the entire project or target:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED
+ *
+ * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m
+ * files before including transport_log.h (consider doing it only for debug
+ * purposes and be very careful not to push such temporary changes to source
+ * control):
+ *
+ * #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+ * #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are
+ * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds
+ * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not
+ * defined).
+ */
+#if defined(TRANSPORT_LOG_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING
+#elif defined(TRANSPORT_LOG_DEF_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED
+#else
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+#endif
+#endif
+
+/* Check censoring at compile time. Evaluates to true when censoring is disabled
+ * (i.e. when secrets will be logged). For example:
+ *
+ * #if TRANSPORT_LOG_SECRETS
+ * char ssn[16];
+ * getSocialSecurityNumber(ssn);
+ * TRANSPORT_LOGI("Customer ssn: %s", ssn);
+ * #endif
+ *
+ * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single
+ * log statement.
+ */
+#define TRANSPORT_LOG_SECRETS \
+ (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING)
+
+/* Static (compile-time) initialization support allows to configure logging
+ * before entering main() function. This mostly useful in C++ where functions
+ * and methods could be called during initialization of global objects. Those
+ * functions and methods could record log messages too and for that reason
+ * static initialization of logging configuration is customizable.
+ *
+ * Macros below allow to specify values to use for initial configuration:
+ * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
+ * TRANSPORT_LOG_MEM_WIDTH in transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default:
+ * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in
+ * transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level
+ * (default: 0 - all levals are "turned on")
+ *
+ * For example, in log_config.c:
+ *
+ * #include <hicn/transport_log.h>
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp";
+ * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD,
+ * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL =
+ * TRANSPORT_LOG_INFO;
+ *
+ * However, to use any of those macros transport_log library must be compiled
+ * with following macros defined:
+ * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define
+ * TRANSPORT_LOG_EXTERN_TAG_PREFIX
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+ *
+ * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX
+ * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used
+ * exactly once somewhere. Otherwise build will fail with link error (undefined
+ * symbol).
+ */
+#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix
+#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \
+ transport_log_format _transport_log_global_format
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \
+ transport_log_output _transport_log_global_output
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \
+ int _transport_log_global_output_lvl
+
+/* Pointer to global format options. Direct modification is not allowed. Use
+ * transport_log_set_mem_width() instead. Could be used to initialize
+ * transport_log_spec structure:
+ *
+ * const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD,
+ * output_callback, 0}; const transport_log_spec g_spec =
+ * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec,
+ * "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_FORMAT \
+ ((const transport_log_format *)&_transport_log_global_format)
+
+/* Pointer to global output variable. Direct modification is not allowed. Use
+ * transport_log_set_output_v() or transport_log_set_output_p() instead. Could
+ * be used to initialize transport_log_spec structure:
+ *
+ * const transport_log_format g_format = {40};
+ * const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT};
+ * TRANSPORT_LOGI_AUX(&g_spec, "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_OUTPUT \
+ ((const transport_log_output *)&_transport_log_global_output)
+
+/* When defined, all library symbols produced by linker will be prefixed with
+ * provided value. That allows to use transport_log library privately in another
+ * libraries without exposing transport_log symbols in their original form (to
+ * avoid possible conflicts with other libraries / components that also could
+ * use transport_log for logging). Value must be without quotes, for example:
+ *
+ * CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_
+ *
+ * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when
+ * building transport_log library AND it also must be defined to the same value
+ * when building a library that uses it. For example, consider fictional
+ * KittyHttp library that wants to use transport_log for logging. First approach
+ * that could be taken is to add transport_log.h and transport_log.c to the
+ * KittyHttp's source code tree directly. In that case it will be enough just to
+ * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script:
+ *
+ * // KittyHttp/CMakeLists.txt
+ * target_compile_definitions(KittyHttp PRIVATE
+ * "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_")
+ *
+ * If KittyHttp doesn't want to include transport_log source code in its source
+ * tree and wants to build transport_log as a separate library than
+ * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined
+ * to KittyHttp_ AND KittyHttp library itself also needs to define
+ * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build
+ * script, as in example above, or by providing a wrapper header that KittyHttp
+ * library will need to use instead of transport_log.h:
+ *
+ * // KittyHttpLogging.h
+ * #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_
+ * #include <hicn/transport_log.h>
+ *
+ * Regardless of the method chosen, the end result is that transport_log symbols
+ * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say
+ * DogeBrowser) also uses transport_log for logging, they will not interferer
+ * with each other. Both will have their own log level, output facility, format
+ * options etc.
+ */
+#ifdef TRANSPORT_LOG_LIBRARY_PREFIX
+#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name
+#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name)
+#define _TRANSPORT_LOG_DECOR(name) \
+ _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name)
+
+#define transport_log_set_tag_prefix \
+ _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix)
+#define transport_log_set_mem_width \
+ _TRANSPORT_LOG_DECOR(transport_log_set_mem_width)
+#define transport_log_set_output_level \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_level)
+#define transport_log_set_output_v \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_v)
+#define transport_log_set_output_p \
+ _TRANSPORT_LOG_DECOR(transport_log_set_output_p)
+#define transport_log_out_stderr_callback \
+ _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback)
+#define _transport_log_tag_prefix \
+ _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix)
+#define _transport_log_global_format \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_format)
+#define _transport_log_global_output \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_output)
+#define _transport_log_global_output_lvl \
+ _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl)
+#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d)
+#define _transport_log_write_aux_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d)
+#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write)
+#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux)
+#define _transport_log_write_mem_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d)
+#define _transport_log_write_mem_aux_d \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d)
+#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem)
+#define _transport_log_write_mem_aux \
+ _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux)
+#define _transport_log_stderr_spec \
+ _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec)
+#endif
+
+#if defined(__printflike)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __printflike(str_index, first_to_check)
+#elif defined(__GNUC__)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __attribute__((format(__printf__, str_index, first_to_check)))
+#else
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check)
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
+#define _TRANSPORT_LOG_FUNCTION __FUNCTION__
+#else
+#define _TRANSPORT_LOG_FUNCTION __func__
+#endif
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#define _TRANSPORT_LOG_INLINE __inline
+#define _TRANSPORT_LOG_IF(cond) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \
+ __pragma(warning(pop))
+#define _TRANSPORT_LOG_WHILE(cond) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \
+ __pragma(warning(pop))
+#else
+#define _TRANSPORT_LOG_INLINE inline
+#define _TRANSPORT_LOG_IF(cond) if (cond)
+#define _TRANSPORT_LOG_WHILE(cond) while (cond)
+#endif
+#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0)
+#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
+ * Use 0 or empty string to disable (default). Common use is to set it to
+ * the process (or build target) name (e.g. to separate client and server
+ * processes). Function will NOT copy provided prefix string, but will store the
+ * pointer. Hence specified prefix string must remain valid. See
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main()
+ * function. See TRANSPORT_LOG_TAG for more information about tag and tag
+ * prefix.
+ */
+void transport_log_set_tag_prefix(const char *const prefix);
+
+/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
+ *
+ * I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo
+ * |<- w bytes ->| |<- w chars ->|
+ *
+ * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details.
+ */
+void transport_log_set_mem_width(const unsigned w);
+
+/* Set "output" log level. See TRANSPORT_LOG_LEVEL and
+ * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels.
+ */
+void transport_log_set_output_level(const int lvl);
+
+/* Put mask is a set of flags that define what fields will be added to each
+ * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be
+ * used to alter its behavior. See transport_log_set_output_v() for more
+ * details.
+ *
+ * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds
+ * (NDEBUG is not defined).
+ */
+enum {
+ TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
+ TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
+ TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
+ TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
+ TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */
+};
+
+typedef struct transport_log_message {
+ int lvl; /* Log level of the message */
+ const char *tag; /* Associated tag (without tag prefix) */
+ char *buf; /* Buffer start */
+ char *e; /* Buffer end (last position where EOL with 0 could be written) */
+ char *p; /* Buffer content end (append position) */
+ char *tag_b; /* Prefixed tag start */
+ char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
+ char *msg_b; /* Message start (expanded format string) */
+} transport_log_message;
+
+/* Type of output callback function. It will be called for each log line allowed
+ * by both "current" and "output" log levels ("enabled" and "turned on").
+ * Callback function is allowed to modify content of the buffers pointed by the
+ * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
+ * is UTF-8 encoded (no BOM mark).
+ */
+typedef void (*transport_log_output_cb)(const transport_log_message *msg,
+ void *arg);
+
+/* Format options. For more details see transport_log_set_mem_width().
+ */
+typedef struct transport_log_format {
+ unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
+} transport_log_format;
+
+/* Output facility.
+ */
+typedef struct transport_log_output {
+ unsigned
+ mask; /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */
+ void *arg; /* User provided output callback argument */
+ transport_log_output_cb callback; /* Output callback function */
+} transport_log_output;
+
+/* Set output callback function.
+ *
+ * Mask allows to control what information will be added to the log line buffer
+ * before callback function is invoked. Default mask value is
+ * TRANSPORT_LOG_PUT_STD.
+ */
+void transport_log_set_output_v(const unsigned mask, void *const arg,
+ const transport_log_output_cb callback);
+static _TRANSPORT_LOG_INLINE void transport_log_set_output_p(
+ const transport_log_output *const output) {
+ transport_log_set_output_v(output->mask, output->arg, output->callback);
+}
+
+/* Used with _AUX macros and allows to override global format and output
+ * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for
+ * values from global configuration. Example:
+ *
+ * static const transport_log_output module_output = {
+ * TRANSPORT_LOG_PUT_STD, 0, custom_output_callback
+ * };
+ * static const transport_log_spec module_spec = {
+ * TRANSPORT_LOG_GLOBAL_FORMAT, &module_output
+ * };
+ * TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
+ *
+ * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details.
+ */
+typedef struct transport_log_spec {
+ const transport_log_format *format;
+ const transport_log_output *output;
+} transport_log_spec;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Execute log statement if condition is true. Example:
+ *
+ * TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this"));
+ * TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this"));
+ *
+ * Keep in mind though, that if condition can't be evaluated at compile time,
+ * then it will be evaluated at run time. This will increase exectuable size
+ * and can have noticeable performance overhead. Try to limit conditions to
+ * expressions that can be evaluated at compile time.
+ */
+#define TRANSPORT_LOG_IF(cond, f) \
+ do { \
+ _TRANSPORT_LOG_IF((cond)) { f; } \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+/* Mark log statement as "secret". Log statements that are marked as secrets
+ * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED).
+ * Example:
+ *
+ * TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card));
+ * TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher
+ * bytes:"));
+ */
+#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f)
+
+/* Check "current" log level at compile time (ignoring "output" log level).
+ * Evaluates to true when specified log level is enabled. For example:
+ *
+ * #if TRANSPORT_LOG_ENABLED_DEBUG
+ * const char *const g_enum_strings[] = {
+ * "enum_value_0", "enum_value_1", "enum_value_2"
+ * };
+ * #endif
+ * // ...
+ * #if TRANSPORT_LOG_ENABLED_DEBUG
+ * TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]);
+ * #endif
+ *
+ * See TRANSPORT_LOG_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL)
+#define TRANSPORT_LOG_ENABLED_VERBOSE \
+ TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL)
+
+/* Check "output" log level at run time (taking into account "current" log
+ * level as well). Evaluates to true when specified log level is turned on AND
+ * enabled. For example:
+ *
+ * if (TRANSPORT_LOG_ON_DEBUG)
+ * {
+ * char hash[65];
+ * sha256(data_ptr, data_sz, hash);
+ * TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash);
+ * }
+ *
+ * See TRANSPORT_LOG_OUTPUT_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ON(lvl) \
+ (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL)
+#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *_transport_log_tag_prefix;
+extern transport_log_format _transport_log_global_format;
+extern transport_log_output _transport_log_global_output;
+extern int _transport_log_global_output_lvl;
+extern const transport_log_spec _transport_log_stderr_spec;
+
+void _transport_log_write_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+void _transport_log_write_aux_d(const char *const func, const char *const file,
+ const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(7, 8);
+void _transport_log_write(const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(3, 4);
+void _transport_log_write_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(4, 5);
+void _transport_log_write_mem_d(const char *const func, const char *const file,
+ const unsigned line, const int lvl,
+ const char *const tag, const void *const d,
+ const unsigned d_sz, const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(8, 9);
+void _transport_log_write_mem_aux_d(const char *const func,
+ const char *const file, const unsigned line,
+ const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(9, 10);
+void _transport_log_write_mem(const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(5, 6);
+void _transport_log_write_mem_aux(const transport_log_spec *const log,
+ const int lvl, const char *const tag,
+ const void *const d, const unsigned d_sz,
+ const char *const fmt, ...)
+ _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Message logging macros:
+ * - TRANSPORT_LOGV("format string", args, ...)
+ * - TRANSPORT_LOGD("format string", args, ...)
+ * - TRANSPORT_LOGI("format string", args, ...)
+ * - TRANSPORT_LOGW("format string", args, ...)
+ * - TRANSPORT_LOGE("format string", args, ...)
+ * - TRANSPORT_LOGF("format string", args, ...)
+ *
+ * Memory logging macros:
+ * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
+ *
+ * Auxiliary logging macros:
+ * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...)
+ *
+ * Auxiliary memory logging macros:
+ * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ *
+ * Preformatted string logging macros:
+ * - TRANSPORT_LOGV_STR("preformatted string");
+ * - TRANSPORT_LOGD_STR("preformatted string");
+ * - TRANSPORT_LOGI_STR("preformatted string");
+ * - TRANSPORT_LOGW_STR("preformatted string");
+ * - TRANSPORT_LOGE_STR("preformatted string");
+ * - TRANSPORT_LOGF_STR("preformatted string");
+ *
+ * Explicit log level and tag macros:
+ * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...)
+ * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args,
+ * ...)
+ * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
+ * "format string", args, ...)
+ *
+ * Format string follows printf() conventions. Both data_ptr and data_sz could
+ * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
+ * match format specifiers in format string.
+ *
+ * Library assuming UTF-8 encoding for all strings (char *), including format
+ * string itself.
+ */
+#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#else
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, log, lvl, tag, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+ do { \
+ if (TRANSPORT_LOG_ON(lvl)) \
+ _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+ __LINE__, log, lvl, tag, d, d_sz, \
+ __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+#endif
+
+static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) {
+ (void)dummy;
+}
+
+#define _TRANSPORT_LOG_UNUSED(...) \
+ do { \
+ _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \
+ } \
+ _TRANSPORT_LOG_ONCE
+
+#if TRANSPORT_LOG_ENABLED_VERBOSE
+#define TRANSPORT_LOGV(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_DEBUG
+#define TRANSPORT_LOGD(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_INFO
+#define TRANSPORT_LOGI(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_WARN
+#define TRANSPORT_LOGW(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_ERROR
+#define TRANSPORT_LOGE(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_FATAL
+#define TRANSPORT_LOGF(...) \
+ TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(log, ...) \
+ TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \
+ __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...) \
+ TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \
+ d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s))
+#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s))
+#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s))
+#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s))
+#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s))
+#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Output to standard error stream. Library uses it by default, though in few
+ * cases it could be necessary to specify it explicitly. For example, when
+ * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT,
+ * application must define and initialize global output variable:
+ *
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR};
+ *
+ * Another example is when using custom output, stderr could be used as a
+ * fallback when custom output facility failed to initialize:
+ *
+ * transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR);
+ */
+enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD };
+void transport_log_out_stderr_callback(const transport_log_message *const msg,
+ void *arg);
+#define TRANSPORT_LOG_OUT_STDERR \
+ TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback
+
+/* Predefined spec for stderr. Uses global format options
+ * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to
+ * force output to stderr for a particular message. Example:
+ *
+ * f = fopen("foo.log", "w");
+ * if (!f)
+ * TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file");
+ */
+#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec)
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/libtransport/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 <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <atomic>
+#include <cassert>
+#include <cinttypes>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include <stdlib.h>
+
+#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<MemBuf> create(std::size_t capacity);
+ MemBuf(CreateOp, std::size_t capacity);
+
+ /**
+ * Create a new MemBuf, using a single memory allocation to allocate space
+ * for both the MemBuf object and the data storage space.
+ *
+ * This saves one memory allocation. However, it can be wasteful if you
+ * later need to grow the buffer using reserve(). If the buffer needs to be
+ * reallocated, the space originally allocated will not be freed() until the
+ * MemBuf object itself is also freed. (It can also be slightly wasteful in
+ * some cases where you clone this MemBuf and then free the original MemBuf.)
+ */
+ static std::unique_ptr<MemBuf> createCombined(std::size_t capacity);
+
+ /**
+ * Create a new IOBuf, using separate memory allocations for the IOBuf object
+ * for the IOBuf and the data storage space.
+ *
+ * This requires two memory allocations, but saves space in the long run
+ * if you know that you will need to reallocate the data buffer later.
+ */
+ static std::unique_ptr<MemBuf> createSeparate(std::size_t capacity);
+
+ /**
+ * Allocate a new MemBuf chain with the requested total capacity, allocating
+ * no more than maxBufCapacity to each buffer.
+ */
+ static std::unique_ptr<MemBuf> createChain(size_t totalCapacity,
+ std::size_t maxBufCapacity);
+
+ static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true) {
+ return takeOwnership(buf, capacity, capacity, freeFn, userData,
+ freeOnError);
+ }
+
+ MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity,
+ FreeFunction freeFn = nullptr, void* userData = nullptr,
+ bool freeOnError = true)
+ : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {}
+
+ static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+ std::size_t length,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true);
+
+ MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length,
+ FreeFunction freeFn = nullptr, void* userData = nullptr,
+ bool freeOnError = true);
+
+ static std::unique_ptr<MemBuf> wrapBuffer(const void* buf,
+ std::size_t capacity);
+
+ static MemBuf wrapBufferAsValue(const void* buf,
+ std::size_t capacity) noexcept;
+
+ MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept;
+
+ /**
+ * Convenience function to create a new MemBuf object that copies data from a
+ * user-supplied buffer, optionally allocating a given amount of
+ * headroom and tailroom.
+ */
+ static std::unique_ptr<MemBuf> copyBuffer(const void* buf, std::size_t size,
+ std::size_t headroom = 0,
+ std::size_t minTailroom = 0);
+
+ MemBuf(CopyBufferOp op, const void* buf, std::size_t size,
+ std::size_t headroom = 0, std::size_t minTailroom = 0);
+
+ /**
+ * Convenience function to free a chain of MemBufs held by a unique_ptr.
+ */
+ static void destroy(std::unique_ptr<MemBuf>&& data) {
+ auto destroyer = std::move(data);
+ }
+
+ ~MemBuf();
+
+ bool empty() const;
+
+ const uint8_t* data() const { return data_; }
+
+ uint8_t* writableData() { return data_; }
+
+ const uint8_t* tail() const { return data_ + length_; }
+
+ uint8_t* writableTail() { return data_ + length_; }
+
+ std::size_t length() const { return length_; }
+
+ std::size_t headroom() const { return std::size_t(data_ - buffer()); }
+
+ std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); }
+
+ const uint8_t* buffer() const { return buf_; }
+
+ uint8_t* writableBuffer() { return buf_; }
+
+ const uint8_t* bufferEnd() const { return buf_ + capacity_; }
+
+ std::size_t capacity() const { return capacity_; }
+
+ MemBuf* next() { return next_; }
+
+ const MemBuf* next() const { return next_; }
+
+ MemBuf* prev() { return prev_; }
+
+ const MemBuf* prev() const { return prev_; }
+
+ /**
+ * Shift the data forwards in the buffer.
+ *
+ * This shifts the data pointer forwards in the buffer to increase the
+ * headroom. This is commonly used to increase the headroom in a newly
+ * allocated buffer.
+ *
+ * The caller is responsible for ensuring that there is sufficient
+ * tailroom in the buffer before calling advance().
+ *
+ * If there is a non-zero data length, advance() will use memmove() to shift
+ * the data forwards in the buffer. In this case, the caller is responsible
+ * for making sure the buffer is unshared, so it will not affect other MemBufs
+ * that may be sharing the same underlying buffer.
+ */
+ void advance(std::size_t amount) {
+ // In debug builds, assert if there is a problem.
+ assert(amount <= tailroom());
+
+ if (length_ > 0) {
+ memmove(data_ + amount, data_, length_);
+ }
+ data_ += amount;
+ }
+
+ /**
+ * Shift the data backwards in the buffer.
+ *
+ * The caller is responsible for ensuring that there is sufficient headroom
+ * in the buffer before calling retreat().
+ *
+ * If there is a non-zero data length, retreat() will use memmove() to shift
+ * the data backwards in the buffer. In this case, the caller is responsible
+ * for making sure the buffer is unshared, so it will not affect other MemBufs
+ * that may be sharing the same underlying buffer.
+ */
+ void retreat(std::size_t amount) {
+ // In debug builds, assert if there is a problem.
+ assert(amount <= headroom());
+
+ if (length_ > 0) {
+ memmove(data_ - amount, data_, length_);
+ }
+ data_ -= amount;
+ }
+
+ void prepend(std::size_t amount) {
+ data_ -= amount;
+ length_ += amount;
+ }
+
+ void append(std::size_t amount) { length_ += amount; }
+
+ void trimStart(std::size_t amount) {
+ data_ += amount;
+ length_ -= amount;
+ }
+
+ void trimEnd(std::size_t amount) { length_ -= amount; }
+
+ // 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<MemBuf>&& iobuf);
+
+ void appendChain(std::unique_ptr<MemBuf>&& iobuf) {
+ // Just use prependChain() on the next element in our chain
+ next_->prependChain(std::move(iobuf));
+ }
+
+ std::unique_ptr<MemBuf> unlink() {
+ next_->prev_ = prev_;
+ prev_->next_ = next_;
+ prev_ = this;
+ next_ = this;
+ return std::unique_ptr<MemBuf>(this);
+ }
+
+ /**
+ * Remove this MemBuf from its current chain and return a unique_ptr to
+ * the MemBuf that formerly followed it in the chain.
+ */
+ std::unique_ptr<MemBuf> pop() {
+ MemBuf* next = next_;
+ next_->prev_ = prev_;
+ prev_->next_ = next_;
+ prev_ = this;
+ next_ = this;
+ return std::unique_ptr<MemBuf>((next == this) ? nullptr : next);
+ }
+
+ /**
+ * Remove a subchain from this chain.
+ *
+ * Remove the subchain starting at head and ending at tail from this chain.
+ *
+ * Returns a unique_ptr pointing to head. (In other words, ownership of the
+ * head of the subchain is transferred to the caller.) If the caller ignores
+ * the return value and lets the unique_ptr be destroyed, the subchain will
+ * be immediately destroyed.
+ *
+ * The subchain referenced by the specified head and tail must be part of the
+ * same chain as the current MemBuf, but must not contain the current MemBuf.
+ * However, the specified head and tail may be equal to each other (i.e.,
+ * they may be a subchain of length 1).
+ */
+ std::unique_ptr<MemBuf> separateChain(MemBuf* head, MemBuf* tail) {
+ assert(head != this);
+ assert(tail != this);
+
+ head->prev_->next_ = tail->next_;
+ tail->next_->prev_ = head->prev_;
+
+ head->prev_ = tail;
+ tail->next_ = head;
+
+ return std::unique_ptr<MemBuf>(head);
+ }
+
+ /**
+ * Return true if at least one of the MemBufs in this chain are shared,
+ * or false if all of the MemBufs point to unique buffers.
+ *
+ * Use isSharedOne() to only check this MemBuf rather than the entire chain.
+ */
+ bool isShared() const {
+ const MemBuf* current = this;
+ while (true) {
+ if (current->isSharedOne()) {
+ return true;
+ }
+ current = current->next_;
+ if (current == this) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Return true if all MemBufs in this chain are managed by the usual
+ * refcounting mechanism (and so the lifetime of the underlying memory
+ * can be extended by clone()).
+ */
+ bool isManaged() const {
+ const MemBuf* current = this;
+ while (true) {
+ if (!current->isManagedOne()) {
+ return false;
+ }
+ current = current->next_;
+ if (current == this) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Return true if this MemBuf is managed by the usual refcounting mechanism
+ * (and so the lifetime of the underlying memory can be extended by
+ * cloneOne()).
+ */
+ bool isManagedOne() const { return sharedInfo(); }
+
+ /**
+ * Return true if other MemBufs are also pointing to the buffer used by this
+ * MemBuf, and false otherwise.
+ *
+ * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the
+ * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned
+ * from such an MemBuf), it is always considered shared.
+ *
+ * This only checks the current MemBuf, and not other MemBufs in the chain.
+ */
+ bool isSharedOne() const {
+ // If this is a user-owned buffer, it is always considered shared
+ if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) {
+ return true;
+ }
+
+ if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) {
+ return true;
+ }
+
+ if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) {
+ return false;
+ }
+
+ // flag_maybe_shared is set, so we need to check the reference count.
+ // (Checking the reference count requires an atomic operation, which is why
+ // we prefer to only check flag_maybe_shared if possible.)
+ bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
+ if (!shared) {
+ // we're the last one left
+ clearFlags(flag_maybe_shared);
+ }
+ return shared;
+ }
+
+ /**
+ * Ensure that this MemBuf has a unique buffer that is not shared by other
+ * MemBufs.
+ *
+ * unshare() operates on an entire chain of MemBuf objects. If the chain is
+ * shared, it may also coalesce the chain when making it unique. If the
+ * chain is coalesced, subsequent MemBuf objects in the current chain will be
+ * automatically deleted.
+ *
+ * Note that buffers owned by other (non-MemBuf) users are automatically
+ * considered shared.
+ *
+ * Throws std::bad_alloc on error. On error the MemBuf chain will be
+ * unmodified.
+ *
+ * Currently unshare may also throw std::overflow_error if it tries to
+ * coalesce. (TODO: In the future it would be nice if unshare() were smart
+ * enough not to coalesce the entire buffer if the data is too large.
+ * However, in practice this seems unlikely to become an issue.)
+ */
+ void unshare() {
+ if (isChained()) {
+ unshareChained();
+ } else {
+ unshareOne();
+ }
+ }
+
+ /**
+ * Ensure that this MemBuf has a unique buffer that is not shared by other
+ * MemBufs.
+ *
+ * unshareOne() operates on a single MemBuf object. This MemBuf will have a
+ * unique buffer after unshareOne() returns, but other MemBufs in the chain
+ * may still be shared after unshareOne() returns.
+ *
+ * Throws std::bad_alloc on error. On error the MemBuf will be unmodified.
+ */
+ void unshareOne() {
+ if (isSharedOne()) {
+ unshareOneSlow();
+ }
+ }
+
+ /**
+ * Mark the underlying buffers in this chain as shared with external memory
+ * management mechanism. This will make isShared() always returns true.
+ *
+ * This function is not thread-safe, and only safe to call immediately after
+ * creating an MemBuf, before it has been shared with other threads.
+ */
+ void markExternallyShared();
+
+ /**
+ * Mark the underlying buffer that this MemBuf refers to as shared with
+ * external memory management mechanism. This will make isSharedOne() always
+ * returns true.
+ *
+ * This function is not thread-safe, and only safe to call immediately after
+ * creating an MemBuf, before it has been shared with other threads.
+ */
+ void markExternallySharedOne() {
+ SharedInfo* info = sharedInfo();
+ if (info) {
+ info->externallyShared = true;
+ }
+ }
+
+ /**
+ * Ensure that the memory that MemBufs in this chain refer to will continue to
+ * be allocated for as long as the MemBufs of the chain (or any clone()s
+ * created from this point onwards) is alive.
+ *
+ * This only has an effect for user-owned buffers (created with the
+ * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+ * those buffers are unshared.
+ */
+ void makeManaged() {
+ if (isChained()) {
+ makeManagedChained();
+ } else {
+ makeManagedOne();
+ }
+ }
+
+ /**
+ * Ensure that the memory that this MemBuf refers to will continue to be
+ * allocated for as long as this MemBuf (or any clone()s created from this
+ * point onwards) is alive.
+ *
+ * This only has an effect for user-owned buffers (created with the
+ * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+ * those buffers are unshared.
+ */
+ void makeManagedOne() {
+ if (!isManagedOne()) {
+ // We can call the internal function directly; unmanaged implies shared.
+ unshareOneSlow();
+ }
+ }
+
+ // /**
+ // * Coalesce this MemBuf chain into a single buffer.
+ // *
+ // * This method moves all of the data in this MemBuf chain into a single
+ // * contiguous buffer, if it is not already in one buffer. After coalesce()
+ // * returns, this MemBuf will be a chain of length one. Other MemBufs in
+ // the
+ // * chain will be automatically deleted.
+ // *
+ // * After coalescing, the MemBuf will have at least as much headroom as the
+ // * first MemBuf in the chain, and at least as much tailroom as the last
+ // MemBuf
+ // * in the chain.
+ // *
+ // * Throws std::bad_alloc on error. On error the MemBuf chain will be
+ // * unmodified.
+ // *
+ // * Returns ByteRange that points to the data MemBuf stores.
+ // */
+ // ByteRange coalesce() {
+ // const std::size_t newHeadroom = headroom();
+ // const std::size_t newTailroom = prev()->tailroom();
+ // return coalesceWithHeadroomTailroom(newHeadroom, newTailroom);
+ // }
+
+ // /**
+ // * This is similar to the coalesce() method, except this allows to set a
+ // * headroom and tailroom after coalescing.
+ // *
+ // * Returns ByteRange that points to the data MemBuf stores.
+ // */
+ // ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom,
+ // std::size_t newTailroom) {
+ // if (isChained()) {
+ // coalesceAndReallocate(newHeadroom, computeChainDataLength(), this,
+ // newTailroom);
+ // }
+ // return ByteRange(data_, length_);
+ // }
+
+ /**
+ * Ensure that this chain has at least maxLength bytes available as a
+ * contiguous memory range.
+ *
+ * This method coalesces whole buffers in the chain into this buffer as
+ * necessary until this buffer's length() is at least maxLength.
+ *
+ * After coalescing, the MemBuf will have at least as much headroom as the
+ * first MemBuf in the chain, and at least as much tailroom as the last MemBuf
+ * that was coalesced.
+ *
+ * Throws std::bad_alloc or std::overflow_error on error. On error the MemBuf
+ * chain will be unmodified. Throws std::overflow_error if maxLength is
+ * longer than the total chain length.
+ *
+ * Upon return, either enough of the chain was coalesced into a contiguous
+ * region, or the entire chain was coalesced. That is,
+ * length() >= maxLength || !isChained() is true.
+ */
+ void gather(std::size_t maxLength) {
+ if (!isChained() || length_ >= maxLength) {
+ return;
+ }
+ coalesceSlow(maxLength);
+ }
+
+ /**
+ * Return a new MemBuf chain sharing the same data as this chain.
+ *
+ * The new MemBuf chain will normally point to the same underlying data
+ * buffers as the original chain. (The one exception to this is if some of
+ * the MemBufs in this chain contain small internal data buffers which cannot
+ * be shared.)
+ */
+ std::unique_ptr<MemBuf> clone() const;
+
+ /**
+ * Similar to clone(). But returns MemBuf by value rather than heap-allocating
+ * it.
+ */
+ MemBuf cloneAsValue() const;
+
+ /**
+ * Return a new MemBuf with the same data as this MemBuf.
+ *
+ * The new MemBuf returned will not be part of a chain (even if this MemBuf is
+ * part of a larger chain).
+ */
+ std::unique_ptr<MemBuf> cloneOne() const;
+
+ /**
+ * Similar to cloneOne(). But returns MemBuf by value rather than
+ * heap-allocating it.
+ */
+ MemBuf cloneOneAsValue() const;
+
+ /**
+ * Return a new unchained MemBuf that may share the same data as this chain.
+ *
+ * If the MemBuf chain is not chained then the new MemBuf will point to the
+ * same underlying data buffer as the original chain. Otherwise, it will clone
+ * and coalesce the MemBuf chain.
+ *
+ * The new MemBuf will have at least as much headroom as the first MemBuf in
+ * the chain, and at least as much tailroom as the last MemBuf in the chain.
+ *
+ * Throws std::bad_alloc on error.
+ */
+ std::unique_ptr<MemBuf> cloneCoalesced() const;
+
+ /**
+ * This is similar to the cloneCoalesced() method, except this allows to set a
+ * headroom and tailroom for the new MemBuf.
+ */
+ std::unique_ptr<MemBuf> cloneCoalescedWithHeadroomTailroom(
+ std::size_t newHeadroom, std::size_t newTailroom) const;
+
+ /**
+ * Similar to cloneCoalesced(). But returns MemBuf by value rather than
+ * heap-allocating it.
+ */
+ MemBuf cloneCoalescedAsValue() const;
+
+ /**
+ * This is similar to the cloneCoalescedAsValue() method, except this allows
+ * to set a headroom and tailroom for the new MemBuf.
+ */
+ MemBuf cloneCoalescedAsValueWithHeadroomTailroom(
+ std::size_t newHeadroom, std::size_t newTailroom) const;
+
+ /**
+ * Similar to Clone(). But use other as the head node. Other nodes in the
+ * chain (if any) will be allocted on heap.
+ */
+ void cloneInto(MemBuf& other) const { other = cloneAsValue(); }
+
+ /**
+ * Similar to CloneOne(). But to fill an existing MemBuf instead of a new
+ * MemBuf.
+ */
+ void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); }
+
+ /**
+ * Return an iovector suitable for e.g. writev()
+ *
+ * auto iov = buf->getIov();
+ * auto xfer = writev(fd, iov.data(), iov.size());
+ *
+ * Naturally, the returned iovector is invalid if you modify the buffer
+ * chain.
+ */
+ std::vector<struct iovec> getIov() const;
+
+ /**
+ * Update an existing iovec array with the MemBuf data.
+ *
+ * New iovecs will be appended to the existing vector; anything already
+ * present in the vector will be left unchanged.
+ *
+ * Naturally, the returned iovec data will be invalid if you modify the
+ * buffer chain.
+ */
+ void appendToIov(std::vector<struct iovec>* iov) const;
+
+ /**
+ * Fill an iovec array with the MemBuf data.
+ *
+ * Returns the number of iovec filled. If there are more buffer than
+ * iovec, returns 0. This version is suitable to use with stack iovec
+ * arrays.
+ *
+ * Naturally, the filled iovec data will be invalid if you modify the
+ * buffer chain.
+ */
+ size_t fillIov(struct iovec* iov, size_t len) const;
+
+ /**
+ * A helper that wraps a number of iovecs into an MemBuf chain. If count ==
+ * 0, then a zero length buf is returned. This function never returns
+ * nullptr.
+ */
+ static std::unique_ptr<MemBuf> wrapIov(const iovec* vec, size_t count);
+
+ /**
+ * A helper that takes ownerships a number of iovecs into an MemBuf chain. If
+ * count == 0, then a zero length buf is returned. This function never
+ * returns nullptr.
+ */
+ static std::unique_ptr<MemBuf> takeOwnershipIov(const iovec* vec,
+ size_t count,
+ FreeFunction freeFn = nullptr,
+ void* userData = nullptr,
+ bool freeOnError = true);
+
+ /*
+ * Overridden operator new and delete.
+ * These perform specialized memory management to help support
+ * createCombined(), which allocates MemBuf objects together with the buffer
+ * data.
+ */
+ void* operator new(size_t size);
+ void* operator new(size_t size, void* ptr);
+ void operator delete(void* ptr);
+ void operator delete(void* ptr, void* placement);
+
+ // /**
+ // * Iteration support: a chain of MemBufs may be iterated through using
+ // * STL-style iterators over const ByteRanges. Iterators are only
+ // invalidated
+ // * if the MemBuf that they currently point to is removed.
+ // */
+ // Iterator cbegin() const;
+ // Iterator cend() const;
+ // Iterator begin() const;
+ // Iterator end() const;
+
+ /**
+ * Allocate a new null buffer.
+ *
+ * This can be used to allocate an empty MemBuf on the stack. It will have no
+ * space allocated for it. This is generally useful only to later use move
+ * assignment to fill out the MemBuf.
+ */
+ MemBuf() noexcept;
+
+ /**
+ * Move constructor and assignment operator.
+ *
+ * In general, you should only ever move the head of an MemBuf chain.
+ * Internal nodes in an MemBuf chain are owned by the head of the chain, and
+ * should not be moved from. (Technically, nothing prevents you from moving
+ * a non-head node, but the moved-to node will replace the moved-from node in
+ * the chain. This has implications for ownership, since non-head nodes are
+ * owned by the chain head. You are then responsible for relinquishing
+ * ownership of the moved-to node, and manually deleting the moved-from
+ * node.)
+ *
+ * With the move assignment operator, the destination of the move should be
+ * the head of an MemBuf chain or a solitary MemBuf not part of a chain. If
+ * the move destination is part of a chain, all other MemBufs in the chain
+ * will be deleted.
+ */
+ MemBuf(MemBuf&& other) noexcept;
+ MemBuf& operator=(MemBuf&& other) noexcept;
+
+ MemBuf(const MemBuf& other);
+ MemBuf& operator=(const MemBuf& other);
+
+ private:
+ enum FlagsEnum : uintptr_t {
+ // Adding any more flags would not work on 32-bit architectures,
+ // as these flags are stashed in the least significant 2 bits of a
+ // max-align-aligned pointer.
+ flag_free_shared_info = 0x1,
+ flag_maybe_shared = 0x2,
+ flag_mask = flag_free_shared_info | flag_maybe_shared
+ };
+
+ struct SharedInfo {
+ SharedInfo();
+ SharedInfo(FreeFunction fn, void* arg);
+
+ // A pointer to a function to call to free the buffer when the refcount
+ // hits 0. If this is null, free() will be used instead.
+ FreeFunction freeFn;
+ void* userData;
+ std::atomic<uint32_t> refcount;
+ bool externallyShared{false};
+ };
+ // Helper structs for use by operator new and delete
+ struct HeapPrefix;
+ struct HeapStorage;
+ struct HeapFullStorage;
+
+ /**
+ * Create a new MemBuf pointing to an external buffer.
+ *
+ * The caller is responsible for holding a reference count for this new
+ * MemBuf. The MemBuf constructor does not automatically increment the
+ * reference count.
+ */
+ struct InternalConstructor {}; // avoid conflicts
+ MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
+ std::size_t capacity, uint8_t* data, std::size_t length) noexcept;
+
+ void unshareOneSlow();
+ void unshareChained();
+ void makeManagedChained();
+ void coalesceSlow();
+ void coalesceSlow(size_t maxLength);
+ // newLength must be the entire length of the buffers between this and
+ // end (no truncation)
+ void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end,
+ size_t newTailroom);
+ void coalesceAndReallocate(size_t newLength, MemBuf* end) {
+ coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom());
+ }
+ void decrementRefcount();
+ void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
+ void freeExtBuffer();
+
+ static size_t goodExtBufferSize(std::size_t minCapacity);
+ static void initExtBuffer(uint8_t* buf, size_t mallocSize,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn);
+ static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
+ SharedInfo** infoReturn,
+ std::size_t* capacityReturn);
+ static void releaseStorage(HeapStorage* storage, uint16_t freeFlags);
+ static void freeInternalBuf(void* buf, void* userData);
+
+ /*
+ * Member variables
+ */
+
+ /*
+ * Links to the next and the previous MemBuf in this chain.
+ *
+ * The chain is circularly linked (the last element in the chain points back
+ * at the head), and next_ and prev_ can never be null. If this MemBuf is the
+ * only element in the chain, next_ and prev_ will both point to this.
+ */
+ MemBuf* next_{this};
+ MemBuf* prev_{this};
+
+ /*
+ * A pointer to the start of the data referenced by this MemBuf, and the
+ * length of the data.
+ *
+ * This may refer to any subsection of the actual buffer capacity.
+ */
+ uint8_t* data_{nullptr};
+ uint8_t* buf_{nullptr};
+ std::size_t length_{0};
+ std::size_t capacity_{0};
+
+ // Pack flags in least significant 2 bits, sharedInfo in the rest
+ mutable uintptr_t flags_and_shared_info_{0};
+
+ static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags,
+ SharedInfo* info) {
+ uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+ return flags | uinfo;
+ }
+
+ inline SharedInfo* sharedInfo() const {
+ return reinterpret_cast<SharedInfo*>(flags_and_shared_info_ & ~flag_mask);
+ }
+
+ inline void setSharedInfo(SharedInfo* info) {
+ uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+ flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo;
+ }
+
+ inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; }
+
+ // flags_ are changed from const methods
+ inline void setFlags(uintptr_t flags) const {
+ flags_and_shared_info_ |= flags;
+ }
+
+ inline void clearFlags(uintptr_t flags) const {
+ flags_and_shared_info_ &= ~flags;
+ }
+
+ inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) {
+ flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info);
+ }
+
+ struct DeleterBase {
+ virtual ~DeleterBase() {}
+ virtual void dispose(void* p) = 0;
+ };
+
+ template <class UniquePtr>
+ struct UniquePtrDeleter : public DeleterBase {
+ typedef typename UniquePtr::pointer Pointer;
+ typedef typename UniquePtr::deleter_type Deleter;
+
+ explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {}
+ void dispose(void* p) override {
+ try {
+ deleter_(static_cast<Pointer>(p));
+ delete this;
+ } catch (...) {
+ abort();
+ }
+ }
+
+ private:
+ Deleter deleter_;
+ };
+
+ static void freeUniquePtrBuffer(void* ptr, void* userData) {
+ static_cast<DeleterBase*>(userData)->dispose(ptr);
+ }
+};
+
+// template <class UniquePtr>
+// typename std::enable_if<
+// detail::IsUniquePtrToSL<UniquePtr>::value,
+// std::unique_ptr<MemBuf>>::type
+// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) {
+// size_t size = count * sizeof(typename UniquePtr::element_type);
+// auto deleter = new UniquePtrDeleter<UniquePtr>(buf.get_deleter());
+// return takeOwnership(
+// buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter);
+// }
+
+inline std::unique_ptr<MemBuf> MemBuf::copyBuffer(const void* data,
+ std::size_t size,
+ std::size_t headroom,
+ std::size_t minTailroom) {
+ std::size_t capacity = headroom + size + minTailroom;
+ std::unique_ptr<MemBuf> buf = MemBuf::create(capacity);
+ buf->advance(headroom);
+ if (size != 0) {
+ memcpy(buf->writableData(), data, size);
+ }
+ buf->append(size);
+ return buf;
+}
+
+} // namespace utils
diff --git a/libtransport/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 <hicn/transport/utils/branch_prediction.h>
+#include <hicn/transport/utils/spinlock.h>
+
+#include <deque>
+#include <memory>
+#include <mutex>
+
+namespace utils {
+
+template <typename T>
+class ObjectPool {
+ class ObjectDeleter {
+ public:
+ ObjectDeleter(ObjectPool<T> *pool = nullptr) : pool_(pool) {}
+
+ void operator()(T *t) {
+ if (pool_) {
+ pool_->add(t);
+ } else {
+ delete t;
+ }
+ }
+
+ private:
+ ObjectPool<T> *pool_;
+ };
+
+ public:
+ using Ptr = std::unique_ptr<T, ObjectDeleter>;
+
+ ObjectPool() : destructor_(false) {}
+
+ ~ObjectPool() {
+ destructor_ = true;
+ for (auto &ptr : object_pool_) {
+ ptr.reset();
+ }
+ }
+
+ std::pair<bool, Ptr> get() {
+ if (object_pool_.empty()) {
+ return std::make_pair<bool, Ptr>(false, makePtr(nullptr));
+ }
+
+ utils::SpinLock::Acquire locked(object_pool_lock_);
+ auto ret = std::move(object_pool_.front());
+ object_pool_.pop_front();
+ return std::make_pair<bool, Ptr>(true, std::move(ret));
+ }
+
+ void add(T *object) {
+ utils::SpinLock::Acquire locked(object_pool_lock_);
+
+ 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<Ptr> 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 <atomic>
+#include <cstddef>
+
+namespace utils {
+
+/**
+ * NOTE: Single consumer single producer ring buffer
+ */
+template <typename Element, std::size_t Size>
+class CircularFifo {
+ public:
+ enum { Capacity = Size + 1 };
+
+ CircularFifo() : tail_(0), head_(0), size_(0) {}
+ virtual ~CircularFifo() {}
+
+ bool push(const Element& item);
+ bool push(Element&& item);
+ bool pop(Element& item);
+
+ bool wasEmpty() const;
+ bool wasFull() const;
+ bool isLockFree() const;
+ std::size_t size() const;
+
+ private:
+ std::size_t increment(std::size_t idx) const;
+ std::atomic<std::size_t> tail_; // tail(input) index
+ Element array_[Capacity];
+ std::atomic<std::size_t> head_; // head(output) index
+ std::atomic<std::size_t> size_;
+};
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(const Element& item) {
+ const auto current_tail = tail_.load(std::memory_order_relaxed);
+ const auto next_tail = increment(current_tail);
+ if (next_tail != head_.load(std::memory_order_acquire)) {
+ array_[current_tail] = item;
+ tail_.store(next_tail, std::memory_order_release);
+ size_++;
+ return true;
+ }
+
+ // full queue
+ return false;
+}
+
+/**
+ * Push by move
+ */
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(Element&& item) {
+ const auto current_tail = tail_.load(std::memory_order_relaxed);
+ const auto next_tail = increment(current_tail);
+ if (next_tail != head_.load(std::memory_order_acquire)) {
+ array_[current_tail] = std::move(item);
+ tail_.store(next_tail, std::memory_order_release);
+ size_++;
+ return true;
+ }
+
+ // full queue
+ return false;
+}
+
+// Pop by Consumer can only update the head
+// (load with relaxed, store with release)
+// the tail must be accessed with at least acquire
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::pop(Element& item) {
+ const 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 <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasEmpty() const {
+ // snapshot with acceptance of that this comparison operation is not atomic
+ return (head_.load() == tail_.load());
+}
+
+// snapshot with acceptance that this comparison is not atomic
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasFull() const {
+ const auto next_tail =
+ increment(tail_.load()); // acquire, we dont know who call
+ return (next_tail == head_.load());
+}
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::isLockFree() const {
+ return (tail_.is_lock_free() && head_.is_lock_free());
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::increment(std::size_t idx) const {
+ return (idx + 1) % Capacity;
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::size() const {
+ return size_.load(std::memory_order_relaxed);
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/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 <atomic>
+
+namespace utils {
+
+class SpinLock : private std::atomic_flag {
+ public:
+ class Acquire {
+ public:
+ Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); }
+
+ ~Acquire() { spin_lock_.unlock(); }
+
+ // No copies
+ Acquire& operator=(const Acquire&) = delete;
+ Acquire(const Acquire&) = delete;
+
+ private:
+ SpinLock& spin_lock_;
+ };
+
+ SpinLock() { 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 <string>
+
+namespace utils {
+
+class StringTokenizer {
+ public:
+ StringTokenizer(const std::string &str);
+ StringTokenizer(const std::string &str, const std::string &delim);
+
+ bool hasMoreTokens();
+ std::string nextToken();
+
+ private:
+ std::string str_;
+ std::string delimiter_;
+};
+
+} // namespace utils
diff --git a/libtransport/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 <algorithm> // find
+#include <string>
+
+namespace utils {
+
+class Uri {
+ typedef std::string::const_iterator iterator_t;
+
+ public:
+ Uri();
+
+ Uri &parse(const std::string &uri);
+
+ Uri &parseProtocolAndLocator(const std::string &locator);
+
+ std::string getQueryString();
+
+ std::string getPath();
+
+ std::string getProtocol();
+
+ std::string getLocator();
+
+ std::string getPort();
+
+ private:
+ std::string query_string_, path_, protocol_, locator_, port_;
+}; // uri
+
+} // namespace utils