mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
5.1 KiB
242 lines
5.1 KiB
/* |
|
* Copyright (c) 2013-2024, 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 <string> |
|
#include <functional> |
|
#include <memory> |
|
#include <mutex> |
|
#include <thread> |
|
#include <utility> |
|
#include <boost/asio.hpp> |
|
|
|
#ifdef ANDROID |
|
#ifndef __clang__ |
|
#include <boost/lexical_cast.hpp> |
|
namespace std |
|
{ |
|
template <typename T> |
|
std::string to_string(T value) |
|
{ |
|
return boost::lexical_cast<std::string>(value); |
|
} |
|
|
|
inline int stoi(const std::string& str) |
|
{ |
|
return boost::lexical_cast<int>(str); |
|
} |
|
} |
|
#endif |
|
#endif |
|
|
|
namespace i2p |
|
{ |
|
namespace util |
|
{ |
|
|
|
template<class T> |
|
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<typename... TArgs> |
|
T * Acquire (TArgs&&... args) |
|
{ |
|
if (!m_Head) return new T(std::forward<TArgs>(args)...); |
|
else |
|
{ |
|
auto tmp = m_Head; |
|
m_Head = static_cast<T*>(*(void * *)m_Head); // next |
|
return new (tmp)T(std::forward<TArgs>(args)...); |
|
} |
|
} |
|
|
|
void Release (T * t) |
|
{ |
|
if (!t) return; |
|
t->~T (); |
|
*(void * *)t = m_Head; // next |
|
m_Head = t; |
|
} |
|
|
|
template<typename... TArgs> |
|
std::unique_ptr<T, std::function<void(T*)> > AcquireUnique (TArgs&&... args) |
|
{ |
|
return std::unique_ptr<T, std::function<void(T*)> >(Acquire (std::forward<TArgs>(args)...), |
|
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1)); |
|
} |
|
|
|
template<typename... TArgs> |
|
std::shared_ptr<T> AcquireShared (TArgs&&... args) |
|
{ |
|
return std::shared_ptr<T>(Acquire (std::forward<TArgs>(args)...), |
|
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1)); |
|
} |
|
|
|
protected: |
|
|
|
void CleanUp (T * head) |
|
{ |
|
while (head) |
|
{ |
|
auto tmp = head; |
|
head = static_cast<T*>(*(void * *)head); // next |
|
::operator delete ((void *)tmp); |
|
} |
|
} |
|
|
|
protected: |
|
|
|
T * m_Head; |
|
}; |
|
|
|
template<class T> |
|
class MemoryPoolMt: private MemoryPool<T> |
|
{ |
|
public: |
|
|
|
MemoryPoolMt () {} |
|
template<typename... TArgs> |
|
T * AcquireMt (TArgs&&... args) |
|
{ |
|
if (!this->m_Head) return new T(std::forward<TArgs>(args)...); |
|
std::lock_guard<std::mutex> l(m_Mutex); |
|
return this->Acquire (std::forward<TArgs>(args)...); |
|
} |
|
|
|
void ReleaseMt (T * t) |
|
{ |
|
std::lock_guard<std::mutex> l(m_Mutex); |
|
this->Release (t); |
|
} |
|
|
|
void ReleaseMt (T * * arr, size_t num) |
|
{ |
|
if (!arr || !num) return; |
|
std::lock_guard<std::mutex> l(m_Mutex); |
|
for (size_t i = 0; i < num; i++) |
|
this->Release (arr[i]); |
|
} |
|
|
|
template<template<typename, typename...>class C, typename... R> |
|
void ReleaseMt(const C<T *, R...>& c) |
|
{ |
|
std::lock_guard<std::mutex> l(m_Mutex); |
|
for (auto& it: c) |
|
this->Release (it); |
|
} |
|
|
|
template<typename... TArgs> |
|
std::shared_ptr<T> AcquireSharedMt (TArgs&&... args) |
|
{ |
|
return std::shared_ptr<T>(AcquireMt (std::forward<TArgs>(args)...), |
|
std::bind<void (MemoryPoolMt<T>::*)(T *)> (&MemoryPoolMt<T>::ReleaseMt, this, std::placeholders::_1)); |
|
} |
|
|
|
void CleanUpMt () |
|
{ |
|
T * head; |
|
{ |
|
std::lock_guard<std::mutex> 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 () {} |
|
|
|
auto& GetIOService () { return m_Service; } |
|
bool IsRunning () const { return m_IsRunning; }; |
|
|
|
void StartIOService (); |
|
void StopIOService (); |
|
|
|
void SetName (std::string_view name); |
|
|
|
private: |
|
|
|
void Run (); |
|
|
|
private: |
|
|
|
std::string m_Name; |
|
volatile bool m_IsRunning; |
|
std::unique_ptr<std::thread> m_Thread; |
|
boost::asio::io_context m_Service; |
|
}; |
|
|
|
class RunnableServiceWithWork: public RunnableService |
|
{ |
|
protected: |
|
|
|
RunnableServiceWithWork (const std::string& name): |
|
RunnableService (name), m_Work (GetIOService ().get_executor ()) {} |
|
|
|
private: |
|
|
|
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_Work; |
|
}; |
|
|
|
void SetThreadName (const char *name); |
|
|
|
template<typename T> |
|
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
|
|
|