From b4f8045a4e1543b657af8cf04e4188f791b10597 Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Thu, 23 Jul 2015 19:46:06 +0200 Subject: Imported Upstream version 0.3.0 --- src/utils/block_allocator.h | 147 +++++++++++++++++++++++++++ src/utils/dynamic_load.h | 80 +++++++++++++++ src/utils/filtered_data.h | 124 +++++++++++++++++++++++ src/utils/log.cpp | 165 ++++++++++++++++++++++++++++++ src/utils/log.h | 83 +++++++++++++++ src/utils/out.cpp | 55 ++++++++++ src/utils/out.h | 68 +++++++++++++ src/utils/queue.h | 184 ++++++++++++++++++++++++++++++++++ src/utils/sessions.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++++ src/utils/sessions.h | 76 ++++++++++++++ src/utils/spinlock.h | 73 ++++++++++++++ 11 files changed, 1293 insertions(+) create mode 100644 src/utils/block_allocator.h create mode 100644 src/utils/dynamic_load.h create mode 100644 src/utils/filtered_data.h create mode 100644 src/utils/log.cpp create mode 100644 src/utils/log.h create mode 100644 src/utils/out.cpp create mode 100644 src/utils/out.h create mode 100644 src/utils/queue.h create mode 100644 src/utils/sessions.cpp create mode 100644 src/utils/sessions.h create mode 100644 src/utils/spinlock.h (limited to 'src/utils') 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 . +*/ +//------------------------------------------------------------------------------ +#ifndef BLOCK_ALLOCATOR_H +#define BLOCK_ALLOCATOR_H +//------------------------------------------------------------------------------ +#include // 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}; inext; + --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}; inext = (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 . +*/ +//------------------------------------------------------------------------------ +#ifndef DYNAMIC_LOAD_H +#define DYNAMIC_LOAD_H +//------------------------------------------------------------------------------ +#include + +#include +//------------------------------------------------------------------------------ +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 + 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(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 . +*/ +//------------------------------------------------------------------------------ +#ifndef FILTERED_DATA_H +#define FILTERED_DATA_H +//------------------------------------------------------------------------------ +#include +#include + +#include + +#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; + +} // 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 . +*/ +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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(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 . +*/ +//------------------------------------------------------------------------------ +#ifndef LOG_H +#define LOG_H +//------------------------------------------------------------------------------ +#include +//------------------------------------------------------------------------------ +#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 . +*/ +//------------------------------------------------------------------------------ +#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 . +*/ +//------------------------------------------------------------------------------ +#ifndef OUT_H +#define OUT_H +//------------------------------------------------------------------------------ +#include +//------------------------------------------------------------------------------ +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 . +*/ +//------------------------------------------------------------------------------ +#ifndef QUEUE_H +#define QUEUE_H +//------------------------------------------------------------------------------ +#include +#include + +#include "utils/block_allocator.h" +#include "utils/spinlock.h" +//------------------------------------------------------------------------------ +namespace NST +{ +namespace utils +{ + +template +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; + + 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::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 . +*/ +//------------------------------------------------------------------------------ +#include + +#include // for inet_ntop(), ntohs() +#include // for AF_INET/AF_INET6 +#include + +#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 +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 . +*/ +//------------------------------------------------------------------------------ +#ifndef SESSIONS_H +#define SESSIONS_H +//------------------------------------------------------------------------------ +#include +#include +#include + +#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 . +*/ +//------------------------------------------------------------------------------ +#ifndef SPINLOCK_H +#define SPINLOCK_H +//------------------------------------------------------------------------------ +#include // for std::lock_guard + +#include +//------------------------------------------------------------------------------ +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; + +private: + mutable pthread_spinlock_t spinlock; +}; + +} // namespace utils +} // namespace NST +//------------------------------------------------------------------------------ +#endif//SPINLOCK_H +//------------------------------------------------------------------------------ -- cgit v1.2.3