summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorAndrew Shadura <andrew.shadura@collabora.co.uk>2015-07-23 19:46:06 +0200
committerAndrew Shadura <andrew.shadura@collabora.co.uk>2015-07-23 19:46:06 +0200
commitb4f8045a4e1543b657af8cf04e4188f791b10597 (patch)
tree1da11d863f6d25b907c9f1507ff1ae5f188a7e3c /src/utils
Imported Upstream version 0.3.0
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/block_allocator.h147
-rw-r--r--src/utils/dynamic_load.h80
-rw-r--r--src/utils/filtered_data.h124
-rw-r--r--src/utils/log.cpp165
-rw-r--r--src/utils/log.h83
-rw-r--r--src/utils/out.cpp55
-rw-r--r--src/utils/out.h68
-rw-r--r--src/utils/queue.h184
-rw-r--r--src/utils/sessions.cpp238
-rw-r--r--src/utils/sessions.h76
-rw-r--r--src/utils/spinlock.h73
11 files changed, 1293 insertions, 0 deletions
diff --git a/src/utils/block_allocator.h b/src/utils/block_allocator.h
new file mode 100644
index 0000000..798e4ba
--- /dev/null
+++ b/src/utils/block_allocator.h
@@ -0,0 +1,147 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: BlockAllocator for fixed size Chunks of memory
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef BLOCK_ALLOCATOR_H
+#define BLOCK_ALLOCATOR_H
+//------------------------------------------------------------------------------
+#include <cstring> // for memset()
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+// May throw std::bad_alloc() when memory is not enough
+class BlockAllocator
+{
+ struct Chunk
+ {
+ Chunk* next; // used only for free chunks in list
+ };
+public:
+
+ BlockAllocator() noexcept
+ : chunk {0}
+ , block {0}
+ , limit {0}
+ , nfree {0}
+ , allocated{0}
+ , blocks{nullptr}
+ , list {nullptr}
+ {
+ }
+
+ ~BlockAllocator()
+ {
+ for(std::size_t i {0}; i<allocated; i++)
+ {
+ delete[] ((char*)blocks[i]);
+ }
+ delete[] blocks;
+ }
+
+ void init_allocation(std::size_t chunk_size,
+ std::size_t block_size,
+ std::size_t block_limit)
+ {
+ chunk = chunk_size;
+ block = block_size;
+ limit = block_limit;
+
+ blocks = new Chunk*[limit];
+ memset(blocks, 0, sizeof(Chunk*)*limit);
+ list = new_block();
+ }
+
+ inline void* allocate()
+ {
+ if(list == nullptr)
+ {
+ if(allocated == limit) // all blocks are allocated!
+ {
+ increase_blocks_limit();
+ }
+
+ list = new_block();
+ }
+
+ Chunk* c {list};
+ list = list->next;
+ --nfree;
+ return c;
+ }
+
+ inline void deallocate(void* ptr)
+ {
+ Chunk* c {(Chunk*) ptr};
+ c->next = list;
+ list = c;
+ ++nfree;
+ }
+
+ // limits
+ inline std::size_t max_chunks() const { return block*limit; }
+ inline std::size_t max_memory() const { return block*limit*chunk; }
+ inline std::size_t max_blocks() const { return limit; }
+ inline std::size_t free_chunks()const { return nfree; }
+
+private:
+ Chunk* new_block()
+ {
+ char* ptr {new char[block*chunk]};
+ for(std::size_t i {0}; i<block-1; ++i)
+ {
+ ((Chunk*) &ptr[i * chunk])->next = (Chunk*) &ptr[(i + 1) * chunk];
+ }
+ ((Chunk*) &ptr[(block - 1) * chunk])->next = nullptr;
+ blocks[allocated] = (Chunk*) ptr;
+ ++allocated;
+ nfree += block;
+ return (Chunk*) ptr;
+ }
+
+ void increase_blocks_limit()
+ {
+ const std::size_t new_limit {limit * 2}; // increase soft limit by twice
+
+ Chunk** new_blocks {new Chunk*[new_limit]}; // allocate new array of blocks pointers
+ limit = new_limit;
+ memcpy(new_blocks, blocks, sizeof(Chunk*)*allocated); // copy pointers of existing blocks
+ memset(&new_blocks[allocated], 0, sizeof(Chunk*)*(limit-allocated)); // fill pointers for new blocks by NULL
+
+ delete[] blocks; // delete old array of blocks pointers
+ blocks = new_blocks; // set new array
+ }
+
+ std::size_t chunk; // chunk size
+ std::size_t block; // num chunks in block
+ std::size_t limit; // max blocks, soft limit
+ std::size_t nfree; // num of avaliable chunks
+ std::size_t allocated;// num of allocated blocks, up to limit
+ Chunk** blocks; // array of blocks
+ Chunk* list; // list of free chunks
+};
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//BLOCK_ALLOCATOR_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/dynamic_load.h b/src/utils/dynamic_load.h
new file mode 100644
index 0000000..9b5becc
--- /dev/null
+++ b/src/utils/dynamic_load.h
@@ -0,0 +1,80 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Wrapper for dlopen and related functions
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef DYNAMIC_LOAD_H
+#define DYNAMIC_LOAD_H
+//------------------------------------------------------------------------------
+#include <stdexcept>
+
+#include <dlfcn.h>
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+class DynamicLoad
+{
+public:
+ class DLException : public std::runtime_error
+ {
+ public:
+ explicit DLException(const std::string& msg) : std::runtime_error{msg} { }
+ };
+
+protected:
+ explicit DynamicLoad(const std::string& file)
+ {
+ handle = dlopen(file.c_str(), RTLD_LAZY);
+ if(handle == nullptr)
+ {
+ throw DLException{std::string{"Loading dynamic module: "} + file + " failed with error:" + dlerror()};
+ }
+ }
+ ~DynamicLoad()
+ {
+ dlclose(handle);
+ }
+
+ template<typename SymbolPtr>
+ inline void load_address_of(const std::string& name, SymbolPtr& address)
+ {
+ static_assert(sizeof(void*) == sizeof(SymbolPtr), "object pointer and function pointer sizes must be equal");
+
+ // suppression warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object
+ using hook_dlsym_t = SymbolPtr (*)(void *, const char *);
+
+ address = reinterpret_cast<hook_dlsym_t>(dlsym)(handle, name.c_str());
+ if(address == nullptr)
+ {
+ throw DLException{std::string{"Loading symbol "} + name + " failed with error:" + dlerror()};
+ }
+ }
+
+private:
+ void* handle;
+};
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//DYNAMIC_LOAD_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/filtered_data.h b/src/utils/filtered_data.h
new file mode 100644
index 0000000..9f0745b
--- /dev/null
+++ b/src/utils/filtered_data.h
@@ -0,0 +1,124 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Structure for passing filtered data to Analysis module.
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef FILTERED_DATA_H
+#define FILTERED_DATA_H
+//------------------------------------------------------------------------------
+#include <cstdint>
+#include <cassert>
+
+#include <sys/time.h>
+
+#include "utils/sessions.h"
+#include "utils/queue.h"
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+struct FilteredData
+{
+ using Direction = NST::utils::Session::Direction;
+public:
+ NetworkSession* session{nullptr}; // pointer to immutable session in Filtration
+ struct timeval timestamp; // timestamp of last collected packet
+ Direction direction; // direction of data transmission
+
+ uint32_t dlen{0}; // length of filtered data
+ uint8_t* data{cache}; // pointer to data in memory. {Readonly. Always points to proper memory buffer}
+
+private:
+ const static int CACHE_SIZE {4000};
+ uint8_t cache[CACHE_SIZE];
+ uint8_t* memory{nullptr};
+ uint32_t memsize{0};
+
+public:
+ // disable copying
+ FilteredData(const FilteredData&) = delete;
+ FilteredData& operator=(const FilteredData&) = delete;
+
+ inline FilteredData() noexcept : data{cache} {}
+ inline ~FilteredData() {
+ delete[] memory;
+ }
+
+ inline uint32_t capacity() const
+ {
+ if (nullptr == memory)
+ {
+ assert(data == cache);
+ return CACHE_SIZE;
+ }
+ return memsize;
+ }
+
+ // Resize capacity with data safety
+ void resize(uint32_t newsize)
+ {
+ if (capacity() >= newsize) return; // not resize less
+
+ if (nullptr == memory)
+ {
+ memory = new uint8_t[newsize];
+ if (dlen)
+ {
+ memcpy(memory, cache, dlen);
+ }
+ memsize = newsize;
+ data = memory;
+ }
+ else // have some filled memory
+ {
+ uint8_t* mem {new uint8_t[newsize]};
+ if (dlen)
+ {
+ memcpy(mem, memory, dlen);
+ }
+ data = mem;
+ delete[] memory;
+ memory = mem;
+ memsize = newsize;
+ }
+ }
+
+ // Reset data. Release free memory if allocated
+ inline void reset()
+ {
+ if (nullptr != memory)
+ {
+ delete[] memory;
+ memory = nullptr;
+ }
+ memsize = 0;
+ dlen = 0;
+ data = cache;
+ }
+};
+
+using FilteredDataQueue = Queue<FilteredData>;
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//FILTERED_DATA_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/log.cpp b/src/utils/log.cpp
new file mode 100644
index 0000000..d26f053
--- /dev/null
+++ b/src/utils/log.cpp
@@ -0,0 +1,165 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Reentrant logger implementation
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#include <cstdarg>
+#include <cstdio>
+#include <cerrno>
+#include <iostream>
+#include <stdexcept>
+#include <system_error>
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "utils/log.h"
+#include "utils/out.h"
+//------------------------------------------------------------------------------
+/* http://www.unix.org/whitepapers/reentrant.html
+ The POSIX.1 and C-language functions that operate on character streams
+ (represented by pointers to objects of type FILE) are required by POSIX.1c
+ to be implemented in such a way that reentrancy is achieved
+ (see ISO/IEC 9945:1-1996, ยง8.2). This requirement has a drawback; it imposes
+ substantial performance penalties because of the synchronization that must
+ be built into the implementations of the functions for the sake of reentrancy.
+*/
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+static FILE* log_file {::stderr};
+static bool own_file {false};
+
+namespace // unnanmed
+{
+
+static std::string get_pid()
+{
+ char buff[8]={'\0'};
+ sprintf(buff,"%ld",(long)getpid());
+ return std::string{buff};
+}
+
+static FILE* try_open(const std::string& file_name)
+{
+ FILE* file {fopen(file_name.c_str(), "w")};
+ if(file == nullptr)
+ {
+ throw std::system_error{errno, std::system_category(),
+ "Error in opening file."};
+ }
+ chmod(file_name.c_str(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if(flock(fileno(file), LOCK_EX | LOCK_NB))
+ {
+ fclose(file);
+ throw std::system_error{errno, std::system_category(),
+ "Log file already locked"};
+ }
+ return file;
+}
+
+} // namespace unnamed
+
+Log::Global::Global(const std::string& path)
+{
+ const std::string log_path{"/tmp/nfstrace"};
+
+ if(log_file != ::stderr)
+ {
+ throw std::runtime_error{"Global Logger already have been created"};
+ }
+
+ if(path.empty()) return;
+
+ struct stat s;
+ if(stat(log_path.c_str(), &s)) // check destination folder exists
+ {
+ if(mkdir(log_path.c_str(), ALLPERMS)) // create directory for nfs logs
+ {
+ throw std::system_error{errno, std::system_category(),
+ "Can't create log directory."};
+ }
+ }
+ std::string tmp{log_path + '/' + path + ".log"};
+ FILE* file {nullptr};
+ try
+ {
+ file = try_open(tmp);
+ }
+ catch(std::system_error& err)
+ {
+ tmp = log_path + '/' + path + '-' + get_pid() + ".log";
+ file = try_open(tmp);
+ }
+ if(utils::Out message{})
+ {
+ message << "Log folder: " << log_path;
+ }
+
+ log_file = file;
+ own_file = true;
+}
+
+Log::Global::~Global()
+{
+ if(own_file)
+ {
+ flock(fileno(log_file), LOCK_UN);
+ fclose(log_file);
+ own_file = false;
+ log_file = ::stderr;
+ }
+}
+
+Log::Log()
+: std::stringbuf {ios_base::out}
+, std::ostream {nullptr}
+{
+ std::stringbuf::setp(buffer, buffer+sizeof(buffer));
+ std::ostream::init(static_cast<std::stringbuf*>(this));
+ std::ostream::put('\n');
+}
+
+Log::~Log()
+{
+ size_t len = pptr() - pbase();
+ fwrite(pbase(), len, 1, log_file);
+}
+
+void Log::message(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(log_file, format, args);
+ va_end(args);
+}
+
+void Log::flush()
+{
+ fflush(log_file);
+}
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
diff --git a/src/utils/log.h b/src/utils/log.h
new file mode 100644
index 0000000..4b45143
--- /dev/null
+++ b/src/utils/log.h
@@ -0,0 +1,83 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Reentrant logger interface
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef LOG_H
+#define LOG_H
+//------------------------------------------------------------------------------
+#include <sstream>
+//------------------------------------------------------------------------------
+#ifdef NDEBUG
+#define TRACE(...)
+#else
+#define STRINGIZE(x) DO_STRINGIZE(x)
+#define DO_STRINGIZE(x) #x
+// TODO: DANGEROUS MACRO ! Passing custom client string as format to printf().
+// May be cause of SIGSEGV
+#define TRACE(...) {\
+ NST::utils::Log::message("\n" __FILE__ ":" STRINGIZE(__LINE__) ": " __VA_ARGS__);\
+ NST::utils::Log::flush();\
+}
+#endif
+
+#define LOG(...) {\
+ NST::utils::Log::message("\n" __VA_ARGS__);\
+}
+
+#define LOGONCE(...) {\
+ static bool notyet = true; \
+ if(notyet) { LOG(__VA_ARGS__); notyet = false; }\
+}
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+class Log : private std::stringbuf, public std::ostream
+{
+public:
+ // helper for creation and destruction logging subsystem
+ // isn't thread-safe!
+ struct Global
+ {
+ explicit Global(const std::string& file_path);
+ ~Global();
+ Global(const Global&) = delete;
+ Global& operator=(const Global&) = delete;
+ };
+
+ Log();
+ ~Log();
+ Log(const Log&) = delete;
+ Log& operator=(const Log&) = delete;
+
+ // lightweight logging
+ static void message(const char* format, ...);
+ static void flush();
+private:
+ char buffer[256];
+};
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//LOG_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/out.cpp b/src/utils/out.cpp
new file mode 100644
index 0000000..34936a7
--- /dev/null
+++ b/src/utils/out.cpp
@@ -0,0 +1,55 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: User output
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#include "utils/out.h"
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+static Out::Level global = Out::Level::Info;
+
+Out::Global::Global(const Level verbose_level)
+{
+ global = verbose_level;
+}
+Out::Global::~Global()
+{
+}
+
+Out::Level Out::Global::get_level()
+{
+ return global;
+}
+
+Out::Out(Level level)
+: std::ostream{ (global >= level) ? std::cout.rdbuf() : nullptr }
+{
+}
+Out::~Out()
+{
+ std::ostream::put('\n');
+}
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
diff --git a/src/utils/out.h b/src/utils/out.h
new file mode 100644
index 0000000..f0f7447
--- /dev/null
+++ b/src/utils/out.h
@@ -0,0 +1,68 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Interface to print out user information
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef OUT_H
+#define OUT_H
+//------------------------------------------------------------------------------
+#include <iostream>
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+class Out : public std::ostream
+{
+public:
+ enum class Level : int // verbosity level
+ {
+ Silent = 0,
+ Info = 1,
+ All = 2,
+ };
+
+ // helper for creation and destruction global level of verbosity
+ struct Global
+ {
+ explicit Global(const Level verbose_level);
+ ~Global();
+ Global(const Global&) = delete;
+ Global& operator=(const Global&) = delete;
+
+ static Level get_level(); // return global level of verbosity
+ };
+
+ explicit Out(Level level=Level::Info); // verbose level of message
+ ~Out();
+ Out(const Out&) = delete;
+ Out& operator=(const Out&) = delete;
+};
+
+inline bool operator >=(const Out::Level a, const Out::Level b)
+{
+ return (int)a >= (int)b;
+}
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//OUT_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/queue.h b/src/utils/queue.h
new file mode 100644
index 0000000..941c543
--- /dev/null
+++ b/src/utils/queue.h
@@ -0,0 +1,184 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Special Queue for fixed size elements without copying them
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef QUEUE_H
+#define QUEUE_H
+//------------------------------------------------------------------------------
+#include <memory>
+#include <type_traits>
+
+#include "utils/block_allocator.h"
+#include "utils/spinlock.h"
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+template <typename T>
+class Queue
+{
+ struct Element // an element of the queue
+ {
+ Element* prev;
+ T data;
+ };
+
+ struct ElementDeleter
+ {
+ inline explicit ElementDeleter() noexcept : queue{nullptr} {}
+ inline explicit ElementDeleter(Queue* q) noexcept : queue{q} {}
+
+ inline void operator()(T* const pointer) const
+ {
+ if(pointer /*&& queue - dont check - optimization*/)
+ {
+ queue->deallocate(pointer);
+ }
+ }
+
+ Queue* queue;
+ };
+
+public:
+
+ using Ptr = std::unique_ptr<T, ElementDeleter>;
+
+ class List // List of elements for client code
+ {
+ public:
+ inline explicit List(Queue& q) : queue{&q}
+ {
+ ptr = queue->pop_list();
+ }
+ List(const List&) = delete;
+ List& operator=(const List&) = delete;
+ inline ~List()
+ {
+ while(ptr)
+ {
+ free_current();
+ }
+ }
+
+ inline operator bool() const { return ptr; } // is empty?
+ inline const T& data() const { return ptr->data; } // get data
+ inline Ptr get_current() // return element and switch to next
+ {
+ Element* tmp {ptr};
+ ptr = ptr->prev;
+ return Ptr{&tmp->data, ElementDeleter{queue}};
+ }
+ inline void free_current() // deallocate element and switch to next
+ {
+ Element* tmp {ptr->prev};
+ queue->deallocate(ptr);
+ ptr = tmp;
+ }
+ private:
+ Element* ptr;
+ Queue* queue;
+ };
+
+
+ Queue(uint32_t size, uint32_t limit) : last{nullptr}, first{nullptr}
+ {
+ allocator.init_allocation(sizeof(Element), size, limit);
+ }
+ ~Queue()
+ {
+ List list{*this}; // deallocate items by destructor of List
+ }
+
+ inline T* allocate()
+ {
+ static_assert(std::is_nothrow_constructible<T>::value,
+ "The construction of T must not to throw any exception");
+
+ Spinlock::Lock lock{a_spinlock};
+ Element* e {(Element*)allocator.allocate()}; // may throw std::bad_alloc
+ auto ptr = &(e->data);
+ ::new(ptr)T; // only call constructor of T (placement)
+ return ptr;
+ }
+
+ inline void deallocate(T* ptr)
+ {
+ ptr->~T(); // placement allocation functions syntax is used
+ Element* e { (Element*)( ((char*)ptr) - sizeof(Element*) ) };
+ deallocate(e);
+ }
+
+ inline void push(T* ptr)
+ {
+ Element* e { (Element*)( ((char*)ptr) - sizeof(Element*) ) };
+ Spinlock::Lock lock{q_spinlock};
+ if(last)
+ {
+ last->prev = e;
+ last = e;
+ }
+ else // queue is empty
+ {
+ last = first = e;
+ }
+ }
+
+ inline Element* pop_list() // take out list of all queued elements
+ {
+ Element* list {nullptr};
+ if(last)
+ {
+ Spinlock::Lock lock{q_spinlock};
+ if(last)
+ {
+ list = first;
+ last->prev = nullptr; // set end of list
+ last = first = nullptr;
+ }
+ }
+ return list;
+ }
+
+private:
+ // accessible from Queue::List and Queue::Ptr
+ inline void deallocate(Element* e)
+ {
+ Spinlock::Lock lock{a_spinlock};
+ allocator.deallocate(e);
+ }
+
+ BlockAllocator allocator;
+ Spinlock a_spinlock; // for allocate/deallocate
+ Spinlock q_spinlock; // for queue push/pop
+
+ // queue empty: last->nullptr<-first
+ // queue filled: last->e<-e<-e<-e<-first
+ // queue push(i): last->i<-e<-e<-e<-e<-first
+ Element* last;
+ Element* first;
+};
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//QUEUE_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/sessions.cpp b/src/utils/sessions.cpp
new file mode 100644
index 0000000..815a226
--- /dev/null
+++ b/src/utils/sessions.cpp
@@ -0,0 +1,238 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Structs for sessions.
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#include <sstream>
+
+#include <arpa/inet.h> // for inet_ntop(), ntohs()
+#include <sys/socket.h> // for AF_INET/AF_INET6
+#include <netdb.h>
+
+#include "utils/out.h"
+#include "utils/sessions.h"
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+std::ostream& operator<<(std::ostream& out, const ApplicationSession& session);
+
+ApplicationSession::ApplicationSession(const NetworkSession& s, Direction from_client)
+: utils::Session (s)
+{
+ if(s.direction != from_client)
+ {
+ //TODO: implement correct swap_src_dst()
+ std::swap(port[0], port[1]);
+ switch(ip_type)
+ {
+ case Session::IPType::v4:
+ std::swap(ip.v4.addr[0], ip.v4.addr[1]);
+ break;
+ case Session::IPType::v6:
+ std::swap(ip.v6.addr[0], ip.v6.addr[1]);
+ break;
+ }
+ }
+
+ // TODO: print network addresses in human readable form and
+ // potential host name lookup may be expensive, to try to use
+ // std::future(async | deferred, ...) and std::promise, to perform
+ // this operation asynchronously
+ std::stringstream stream(std::ios_base::out);
+ stream << *this;
+ session_str = stream.str();
+}
+
+namespace
+{
+
+std::ostream& operator<<(std::ostream& out, const Session::Type type)
+{
+ switch(type)
+ {
+ case Session::Type::TCP: return out << " [TCP]";
+ case Session::Type::UDP: return out << " [UDP]";
+ }
+ return out;
+}
+
+void print_ipv4_port(std::ostream& out, in_addr_t ipv4, in_port_t port)
+{
+ static_assert(sizeof(ipv4) == sizeof(struct in_addr), "they must be equal");
+ char buf[INET_ADDRSTRLEN];
+
+ const char* str {inet_ntop(AF_INET, &ipv4, buf, sizeof(buf))};
+ out << (str ? str : "Invalid IPv4 address")
+ << ':' << ntohs(port);
+}
+
+void print_ipv6_port(std::ostream& out, const uint8_t (&ipv6)[16], in_port_t port)
+{
+ static_assert(sizeof(ipv6) == sizeof(struct in6_addr),"they must be equal");
+ char buf[INET6_ADDRSTRLEN];
+
+ const char* str {inet_ntop(AF_INET6, ipv6, buf, sizeof(buf))};
+ out << (str ? str : "Invalid IPv6 address")
+ << ':' << ntohs(port);
+}
+
+// TODO: getnameinfo call may be expensive
+template<typename SockAddr>
+void print_sockaddr(std::ostream& out, SockAddr& addr)
+{
+ char hostname[1025];
+ char service [65];
+ const int err {getnameinfo((sockaddr*)&addr, sizeof(addr),
+ hostname, sizeof(hostname),
+ service, sizeof(service),
+ NI_NAMEREQD ) };
+ if(err == 0)
+ {
+ out << '(' << hostname << ':' << service << ')';
+ }
+}
+
+void print_ipv4_port_as_hostname_service(std::ostream& out,
+ in_addr_t ipv4,
+ in_port_t port)
+{
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = port;
+ addr.sin_addr.s_addr= ipv4;
+
+ print_sockaddr(out, addr);
+}
+
+void print_ipv6_port_as_hostname_service(std::ostream& out,
+ const uint8_t (&ipv6)[16],
+ in_port_t port)
+{
+ sockaddr_in6 addr;
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = port;
+ addr.sin6_flowinfo = 0;
+ addr.sin6_addr = (in6_addr&)ipv6;
+ addr.sin6_scope_id = 0;
+
+ print_sockaddr(out, addr);
+}
+
+} // unnamed namespace
+
+std::ostream& operator<<(std::ostream& out, const Session& session)
+{
+ print_session(out, session);
+ return out;
+}
+
+void print_session(std::ostream& out, const Session& session)
+{
+ switch(session.ip_type)
+ {
+ case Session::IPType::v4:
+ {
+ print_ipv4_port(out, session.ip.v4.addr[Session::Source],
+ session.port [Session::Source]);
+ out << " --> ";
+ print_ipv4_port(out, session.ip.v4.addr[Session::Destination],
+ session.port [Session::Destination]);
+ }
+ break;
+ case Session::IPType::v6:
+ {
+ print_ipv6_port(out, session.ip.v6.addr[Session::Source],
+ session.port [Session::Source]);
+ out << " --> ";
+ print_ipv6_port(out, session.ip.v6.addr[Session::Destination],
+ session.port [Session::Destination]);
+ }
+ break;
+ }
+ out << session.type;
+}
+
+std::ostream& operator<<(std::ostream& out, const ApplicationSession& session)
+{
+ const bool namelookup {Out::Global::get_level() == Out::Level::All};
+
+ switch(session.ip_type)
+ {
+ case Session::IPType::v4:
+ {
+ {
+ auto& port = session.port [Session::Source];
+ auto& addr = session.ip.v4.addr[Session::Source];
+
+ print_ipv4_port(out, addr, port);
+ if(namelookup)
+ {
+ print_ipv4_port_as_hostname_service(out, addr, port);
+ }
+ }
+ out << " --> ";
+ {
+ auto& port = session.port [Session::Destination];
+ auto& addr = session.ip.v4.addr[Session::Destination];
+
+ print_ipv4_port(out, addr, port);
+ if(namelookup)
+ {
+ print_ipv4_port_as_hostname_service(out, addr, port);
+ }
+ }
+ }
+ break;
+ case Session::IPType::v6:
+ {
+ {
+ auto& port = session.port [Session::Source];
+ auto& addr = session.ip.v6.addr[Session::Source];
+
+ print_ipv6_port(out, addr, port);
+ if(namelookup)
+ {
+ print_ipv6_port_as_hostname_service(out, addr, port);
+ }
+ }
+ out << " --> ";
+ {
+ auto& port = session.port [Session::Destination];
+ auto& addr = session.ip.v6.addr[Session::Destination];
+
+ print_ipv6_port(out, addr, port);
+ if(namelookup)
+ {
+ print_ipv6_port_as_hostname_service(out, addr, port);
+ }
+ }
+ }
+ break;
+ }
+ out << session.type;
+ return out;
+}
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+
diff --git a/src/utils/sessions.h b/src/utils/sessions.h
new file mode 100644
index 0000000..d78c303
--- /dev/null
+++ b/src/utils/sessions.h
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Structs for sessions.
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef SESSIONS_H
+#define SESSIONS_H
+//------------------------------------------------------------------------------
+#include <cstddef>
+#include <cstdint>
+#include <ostream>
+
+#include "api/session.h"
+//------------------------------------------------------------------------------
+#define NST_PUBLIC __attribute__ ((visibility("default")))
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+using Session = NST::API::Session;
+
+// Network layer session
+struct NetworkSession : public Session
+{
+public:
+ NetworkSession()
+ : application {nullptr}
+ , direction {Direction::Unknown}
+ {
+ }
+
+ void* application; // pointer to application protocol implementation
+ Direction direction;
+};
+
+
+// Application layer session
+struct ApplicationSession : public Session
+{
+public:
+ ApplicationSession(const NetworkSession& s, Direction from_client);
+
+ const std::string& str() const { return session_str; }
+private:
+ std::string session_str;
+};
+
+extern "C"
+NST_PUBLIC
+void print_session(std::ostream& out, const Session& session);
+
+std::ostream& operator<<(std::ostream& out, const Session& session);
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//SESSIONS_H
+//------------------------------------------------------------------------------
diff --git a/src/utils/spinlock.h b/src/utils/spinlock.h
new file mode 100644
index 0000000..bc8d25f
--- /dev/null
+++ b/src/utils/spinlock.h
@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+// Author: Yauheni Azaranka
+// Description: Wrapper for pthread spinlock. It implements BasicLockable concept.
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 2 of the License.
+
+ Nfstrace is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#ifndef SPINLOCK_H
+#define SPINLOCK_H
+//------------------------------------------------------------------------------
+#include <mutex> // for std::lock_guard
+
+#include <pthread.h>
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+class Spinlock
+{
+public:
+ Spinlock() noexcept
+ {
+ pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
+ }
+ Spinlock(const Spinlock&) = delete;
+ Spinlock& operator=(const Spinlock&) = delete;
+ ~Spinlock() noexcept
+ {
+ pthread_spin_destroy(&spinlock);
+ }
+
+ bool try_lock() noexcept
+ {
+ return 0 == pthread_spin_trylock(&spinlock);
+ }
+
+ void lock() noexcept
+ {
+ pthread_spin_lock(&spinlock);
+ }
+
+ void unlock() noexcept
+ {
+ pthread_spin_unlock(&spinlock);
+ }
+
+ using Lock = std::lock_guard<Spinlock>;
+
+private:
+ mutable pthread_spinlock_t spinlock;
+};
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------
+#endif//SPINLOCK_H
+//------------------------------------------------------------------------------