/* * Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree */ #ifndef UTIL_H #define UTIL_H #include #include #include #include #include #include #include #ifdef ANDROID #ifndef __clang__ #include namespace std { template std::string to_string(T value) { return boost::lexical_cast(value); } inline int stoi(const std::string& str) { return boost::lexical_cast(str); } } #endif #endif namespace i2p { namespace util { template class MemoryPool { //BOOST_STATIC_ASSERT_MSG(sizeof(T) >= sizeof(void*), "size cannot be less that general pointer size"); public: MemoryPool (): m_Head (nullptr) {} ~MemoryPool () { CleanUp (); } void CleanUp () { CleanUp (m_Head); m_Head = nullptr; } template T * Acquire (TArgs&&... args) { if (!m_Head) return new T(std::forward(args)...); else { auto tmp = m_Head; m_Head = static_cast(*(void * *)m_Head); // next return new (tmp)T(std::forward(args)...); } } void Release (T * t) { if (!t) return; t->~T (); *(void * *)t = m_Head; // next m_Head = t; } template std::unique_ptr > AcquireUnique (TArgs&&... args) { return std::unique_ptr >(Acquire (std::forward(args)...), std::bind (&MemoryPool::Release, this, std::placeholders::_1)); } template std::shared_ptr AcquireShared (TArgs&&... args) { return std::shared_ptr(Acquire (std::forward(args)...), std::bind (&MemoryPool::Release, this, std::placeholders::_1)); } protected: void CleanUp (T * head) { while (head) { auto tmp = head; head = static_cast(*(void * *)head); // next ::operator delete ((void *)tmp); } } protected: T * m_Head; }; template class MemoryPoolMt: private MemoryPool { public: MemoryPoolMt () {} template T * AcquireMt (TArgs&&... args) { if (!this->m_Head) return new T(std::forward(args)...); std::lock_guard l(m_Mutex); return this->Acquire (std::forward(args)...); } void ReleaseMt (T * t) { std::lock_guard l(m_Mutex); this->Release (t); } templateclass C, typename... R> void ReleaseMt(const C& c) { std::lock_guard l(m_Mutex); for (auto& it: c) this->Release (it); } template std::shared_ptr AcquireSharedMt (TArgs&&... args) { return std::shared_ptr(AcquireMt (std::forward(args)...), std::bind::*)(T *)> (&MemoryPoolMt::ReleaseMt, this, std::placeholders::_1)); } void CleanUpMt () { T * head; { std::lock_guard l(m_Mutex); head = this->m_Head; this->m_Head = nullptr; } if (head) this->CleanUp (head); } private: std::mutex m_Mutex; }; class RunnableService { protected: RunnableService (const std::string& name): m_Name (name), m_IsRunning (false) {} virtual ~RunnableService () {} boost::asio::io_service& GetIOService () { return m_Service; } bool IsRunning () const { return m_IsRunning; }; void StartIOService (); void StopIOService (); private: void Run (); private: std::string m_Name; volatile bool m_IsRunning; std::unique_ptr m_Thread; boost::asio::io_service m_Service; }; class RunnableServiceWithWork: public RunnableService { protected: RunnableServiceWithWork (const std::string& name): RunnableService (name), m_Work (GetIOService ()) {} private: boost::asio::io_service::work m_Work; }; void SetThreadName (const char *name); template class SaveStateHelper { public: SaveStateHelper (T& orig): m_Original (orig), m_Copy (orig) {}; ~SaveStateHelper () { m_Original = m_Copy; }; private: T& m_Original; T m_Copy; }; namespace net { int GetMTU (const boost::asio::ip::address& localAddress); int GetMaxMTU (const boost::asio::ip::address_v6& localAddress); // check tunnel broker for ipv6 address const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false); boost::asio::ip::address_v6 GetYggdrasilAddress (); bool IsLocalAddress (const boost::asio::ip::address& addr); bool IsInReservedRange (const boost::asio::ip::address& host); bool IsYggdrasilAddress (const boost::asio::ip::address& addr); bool IsPortInReservedRange (const uint16_t port) noexcept; } } } #endif