atomics have been used for threads stop

This commit is contained in:
brain5lug 2017-10-01 00:46:49 +03:00
parent 8c09a7429c
commit dfa1482ab2
15 changed files with 259 additions and 212 deletions

View file

@ -15,7 +15,7 @@ namespace util
virtual bool init(int argc, char* argv[]); virtual bool init(int argc, char* argv[]);
virtual bool start(); virtual bool start();
virtual bool stop(); virtual bool stop();
virtual void run () {}; virtual void run () {}
bool isDaemon; bool isDaemon;
bool running; bool running;

View file

@ -943,44 +943,50 @@ namespace http {
void HTTPServer::Start () void HTTPServer::Start ()
{ {
bool needAuth; i2p::config::GetOption("http.auth", needAuth); if (!m_IsRunning.load())
std::string user; i2p::config::GetOption("http.user", user); {
std::string pass; i2p::config::GetOption("http.pass", pass); bool needAuth; i2p::config::GetOption("http.auth", needAuth);
/* generate pass if needed */ std::string user; i2p::config::GetOption("http.user", user);
if (needAuth && pass == "") { std::string pass; i2p::config::GetOption("http.pass", pass);
uint8_t random[16]; /* generate pass if needed */
char alnum[] = "0123456789" if (needAuth && pass == "") {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" uint8_t random[16];
"abcdefghijklmnopqrstuvwxyz"; char alnum[] = "0123456789"
pass.resize(sizeof(random)); "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
RAND_bytes(random, sizeof(random)); "abcdefghijklmnopqrstuvwxyz";
for (size_t i = 0; i < sizeof(random); i++) { pass.resize(sizeof(random));
pass[i] = alnum[random[i] % (sizeof(alnum) - 1)]; RAND_bytes(random, sizeof(random));
for (size_t i = 0; i < sizeof(random); i++) {
pass[i] = alnum[random[i] % (sizeof(alnum) - 1)];
}
i2p::config::SetOption("http.pass", pass);
LogPrint(eLogInfo, "HTTPServer: password set to ", pass);
} }
i2p::config::SetOption("http.pass", pass); m_IsRunning.store(true);
LogPrint(eLogInfo, "HTTPServer: password set to ", pass); m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this)));
m_Acceptor.listen ();
Accept ();
} }
m_IsRunning = true;
m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this)));
m_Acceptor.listen ();
Accept ();
} }
void HTTPServer::Stop () void HTTPServer::Stop ()
{ {
m_IsRunning = false; if (m_IsRunning.load())
m_Acceptor.close();
m_Service.stop ();
if (m_Thread)
{ {
m_Thread->join (); m_IsRunning.store(false);
m_Thread = nullptr; m_Acceptor.close();
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
m_Thread = nullptr;
}
} }
} }
void HTTPServer::Run () void HTTPServer::Run ()
{ {
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
try try
{ {

View file

@ -8,6 +8,7 @@
#include <thread> #include <thread>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <sstream> #include <sstream>
#include <atomic>
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p
@ -70,7 +71,7 @@ namespace http
private: private:
bool m_IsRunning; std::atomic_bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;

View file

@ -101,19 +101,19 @@ namespace client
void I2PControlService::Start () void I2PControlService::Start ()
{ {
if (!m_IsRunning) if (!m_IsRunning.load())
{ {
Accept (); Accept ();
m_IsRunning = true; m_IsRunning.store(true);
m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); m_Thread = new std::thread (std::bind (&I2PControlService::Run, this));
} }
} }
void I2PControlService::Stop () void I2PControlService::Stop ()
{ {
if (m_IsRunning) if (m_IsRunning.load())
{ {
m_IsRunning = false; m_IsRunning.store(false);
m_Acceptor.cancel (); m_Acceptor.cancel ();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
@ -127,7 +127,7 @@ namespace client
void I2PControlService::Run () void I2PControlService::Run ()
{ {
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
try { try {
m_Service.run (); m_Service.run ();
@ -160,7 +160,7 @@ namespace client
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket) void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
{ {
socket->async_handshake(boost::asio::ssl::stream_base::server, socket->async_handshake(boost::asio::ssl::stream_base::server,
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket)); std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
} }
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket) void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)

View file

@ -9,6 +9,7 @@
#include <sstream> #include <sstream>
#include <map> #include <map>
#include <set> #include <set>
#include <atomic>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
@ -101,7 +102,7 @@ namespace client
private: private:
std::string m_Password; std::string m_Password;
bool m_IsRunning; std::atomic_bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;

View file

@ -28,10 +28,10 @@ namespace transport
void UPnP::Stop () void UPnP::Stop ()
{ {
if (m_IsRunning) if (m_IsRunning.load())
{ {
LogPrint(eLogInfo, "UPnP: stopping"); LogPrint(eLogInfo, "UPnP: stopping");
m_IsRunning = false; m_IsRunning.store(false);
m_Timer.cancel (); m_Timer.cancel ();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
@ -46,12 +46,15 @@ namespace transport
void UPnP::Start() void UPnP::Start()
{ {
m_IsRunning = true; if (!m_IsRunning.load())
LogPrint(eLogInfo, "UPnP: starting"); {
m_Service.post (std::bind (&UPnP::Discover, this)); m_IsRunning.store(true);
std::unique_lock<std::mutex> l(m_StartedMutex); LogPrint(eLogInfo, "UPnP: starting");
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this))); m_Service.post (std::bind (&UPnP::Discover, this));
m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum std::unique_lock<std::mutex> l(m_StartedMutex);
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum
}
} }
UPnP::~UPnP () UPnP::~UPnP ()
@ -61,7 +64,7 @@ namespace transport
void UPnP::Run () void UPnP::Run ()
{ {
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
try try
{ {

View file

@ -7,6 +7,7 @@
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <atomic>
#include <miniupnpc/miniwget.h> #include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
@ -43,8 +44,8 @@ namespace transport
private: private:
bool m_IsRunning; std::atomic_bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started; std::condition_variable m_Started;
std::mutex m_StartedMutex; std::mutex m_StartedMutex;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;

View file

@ -10,7 +10,6 @@
namespace i2p { namespace i2p {
namespace log { namespace log {
static Log logger;
/** /**
* @brief Maps our loglevel to their symbolic name * @brief Maps our loglevel to their symbolic name
*/ */
@ -70,17 +69,21 @@ namespace log {
void Log::Start () void Log::Start ()
{ {
if (!m_IsRunning) // separate load and store for atomic is valid here
// because only one thread changes m_IsRunning
if (!m_IsRunning.load())
{ {
m_IsRunning = true; m_IsRunning.store(true);
m_Thread = new std::thread (std::bind (&Log::Run, this)); m_Thread = new std::thread (std::bind (&Log::Run, this));
} }
} }
void Log::Stop () void Log::Stop ()
{ {
switch (m_Destination) if (m_IsRunning.load())
{ {
switch (m_Destination)
{
#ifndef _WIN32 #ifndef _WIN32
case eLogSyslog : case eLogSyslog :
closelog(); closelog();
@ -88,19 +91,21 @@ namespace log {
#endif #endif
case eLogFile: case eLogFile:
case eLogStream: case eLogStream:
if (m_LogStream) m_LogStream->flush(); if (m_LogStream) m_LogStream->flush();
break; break;
default: default:
/* do nothing */ /* do nothing */
break; break;
} }
m_IsRunning = false;
m_Queue.WakeUp (); m_IsRunning.store(false);
if (m_Thread) m_Queue.WakeUp ();
{ if (m_Thread)
m_Thread->join (); {
delete m_Thread; m_Thread->join ();
m_Thread = nullptr; delete m_Thread;
m_Thread = nullptr;
}
} }
} }
@ -162,13 +167,13 @@ namespace log {
void Log::Run () void Log::Run ()
{ {
Reopen (); Reopen ();
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
std::shared_ptr<LogMsg> msg; std::shared_ptr<LogMsg> msg;
while (msg = m_Queue.Get ()) while (msg = m_Queue.Get ())
Process (msg); Process (msg);
if (m_LogStream) m_LogStream->flush(); if (m_LogStream) m_LogStream->flush();
if (m_IsRunning) if (m_IsRunning.load(std::memory_order_acquire))
m_Queue.Wait (); m_Queue.Wait ();
} }
} }
@ -215,6 +220,7 @@ namespace log {
} }
Log & Logger() { Log & Logger() {
static Log logger;
return logger; return logger;
} }
} // log } // log

View file

@ -17,6 +17,7 @@
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <thread> #include <thread>
#include <atomic>
#include "Queue.h" #include "Queue.h"
#ifndef _WIN32 #ifndef _WIN32
@ -59,7 +60,7 @@ namespace log {
i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue; i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue;
bool m_HasColors; bool m_HasColors;
std::string m_TimeFormat; std::string m_TimeFormat;
volatile bool m_IsRunning; std::atomic_bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
private: private:
@ -84,8 +85,8 @@ namespace log {
Log (); Log ();
~Log (); ~Log ();
LogType GetLogType () { return m_Destination; }; LogType GetLogType () { return m_Destination; }
LogLevel GetLogLevel () { return m_MinLevel; }; LogLevel GetLogLevel () { return m_MinLevel; }
void Start (); void Start ();
void Stop (); void Stop ();
@ -112,7 +113,7 @@ namespace log {
* @brief Sets format for timestamps in log * @brief Sets format for timestamps in log
* @param format String with timestamp format * @param format String with timestamp format
*/ */
void SetTimeFormat (std::string format) { m_TimeFormat = format; }; void SetTimeFormat (std::string format) { m_TimeFormat = format; }
#ifndef _WIN32 #ifndef _WIN32
/** /**
@ -146,7 +147,7 @@ namespace log {
LogLevel level; /**< message level */ LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */ std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {}; LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {}
}; };
Log & Logger(); Log & Logger();

View file

@ -37,23 +37,28 @@ namespace data
void NetDb::Start () void NetDb::Start ()
{ {
m_Storage.SetPlace(i2p::fs::GetDataDir()); // separate load and store for atomic is valid here
m_Storage.Init(i2p::data::GetBase64SubstitutionTable(), 64); // because only one thread changes m_IsRunning
InitProfilesStorage (); if (!m_IsRunning.load())
m_Families.LoadCertificates (); {
Load (); m_Storage.SetPlace(i2p::fs::GetDataDir());
m_Storage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
InitProfilesStorage ();
m_Families.LoadCertificates ();
Load ();
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold
Reseed (); Reseed ();
m_IsRunning = true; m_IsRunning.store(true);
m_Thread = new std::thread (std::bind (&NetDb::Run, this)); m_Thread = new std::thread (std::bind (&NetDb::Run, this));
}
} }
void NetDb::Stop () void NetDb::Stop ()
{ {
if (m_IsRunning) if (m_IsRunning.load())
{ {
for (auto& it: m_RouterInfos) for (auto& it: m_RouterInfos)
it.second->SaveProfile (); it.second->SaveProfile ();
@ -62,11 +67,11 @@ namespace data
m_Floodfills.clear (); m_Floodfills.clear ();
if (m_Thread) if (m_Thread)
{ {
m_IsRunning = false; m_IsRunning.store(false);
m_Queue.WakeUp (); m_Queue.WakeUp ();
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = nullptr;
} }
m_LeaseSets.clear(); m_LeaseSets.clear();
m_Requests.Stop (); m_Requests.Stop ();
@ -75,8 +80,8 @@ namespace data
void NetDb::Run () void NetDb::Run ()
{ {
uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
try try
{ {
@ -107,7 +112,9 @@ namespace data
numMsgs++; numMsgs++;
} }
} }
if (!m_IsRunning) break;
if (!m_IsRunning.load(std::memory_order_acquire))
break;
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
@ -140,7 +147,7 @@ namespace data
auto numRouters = m_RouterInfos.size (); auto numRouters = m_RouterInfos.size ();
if (numRouters == 0) if (numRouters == 0)
{ {
throw std::runtime_error("No known routers, reseed seems to be totally failed"); throw std::runtime_error("No known routers, reseed seems to be totally failed");
} }
else // we have peers now else // we have peers now
m_FloodfillBootstrap = nullptr; m_FloodfillBootstrap = nullptr;
@ -171,10 +178,10 @@ namespace data
return false; return false;
} }
void NetDb::SetHidden(bool hide) { void NetDb::SetHidden(bool hide) {
// TODO: remove reachable addresses from router info // TODO: remove reachable addresses from router info
m_HiddenMode = hide; m_HiddenMode = hide;
} }
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{ {
@ -330,7 +337,7 @@ namespace data
} }
} }
m_Reseeder->Bootstrap (); m_Reseeder->Bootstrap ();
} }
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
@ -392,7 +399,7 @@ namespace data
void NetDb::VisitStoredRouterInfos(RouterInfoVisitor v) void NetDb::VisitStoredRouterInfos(RouterInfoVisitor v)
{ {
m_Storage.Iterate([v] (const std::string & filename) { m_Storage.Iterate([v] (const std::string & filename) {
auto ri = std::make_shared<i2p::data::RouterInfo>(filename); auto ri = std::make_shared<i2p::data::RouterInfo>(filename);
v(ri); v(ri);
}); });
} }

View file

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <atomic>
#include "Base.h" #include "Base.h"
#include "Gzip.h" #include "Gzip.h"
@ -60,7 +61,7 @@ namespace data
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const; std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
@ -75,21 +76,21 @@ namespace data
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */ /** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide); void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; }
// for web interface // for web interface
int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumRouters () const { return m_RouterInfos.size (); }
int GetNumFloodfills () const { return m_Floodfills.size (); }; int GetNumFloodfills () const { return m_Floodfills.size (); }
int GetNumLeaseSets () const { return m_LeaseSets.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); }
/** visit all lease sets we currently store */ /** visit all lease sets we currently store */
void VisitLeaseSets(LeaseSetVisitor v); void VisitLeaseSets(LeaseSetVisitor v);
@ -100,7 +101,7 @@ namespace data
/** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
void ClearRouterInfos () { m_RouterInfos.clear (); }; void ClearRouterInfos () { m_RouterInfos.clear (); }
private: private:
@ -115,8 +116,8 @@ namespace data
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private: private:
@ -127,7 +128,7 @@ namespace data
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning; std::atomic_bool m_IsRunning;
uint64_t m_LastLoad; uint64_t m_LastLoad;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
@ -144,8 +145,8 @@ namespace data
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */ /** true if in hidden mode */
bool m_HiddenMode; bool m_HiddenMode;
}; };
extern NetDb netdb; extern NetDb netdb;

View file

@ -445,19 +445,25 @@ namespace tunnel
void Tunnels::Start () void Tunnels::Start ()
{ {
m_IsRunning = true; if (!m_IsRunning.load())
m_Thread = new std::thread (std::bind (&Tunnels::Run, this)); {
m_IsRunning.store(true);
m_Thread = new std::thread (std::bind (&Tunnels::Run, this));
}
} }
void Tunnels::Stop () void Tunnels::Stop ()
{ {
m_IsRunning = false; if (m_IsRunning.load())
m_Queue.WakeUp ();
if (m_Thread)
{ {
m_Thread->join (); m_IsRunning.store(false);
delete m_Thread; m_Queue.WakeUp ();
m_Thread = 0; if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = 0;
}
} }
} }
@ -466,7 +472,7 @@ namespace tunnel
std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready
uint64_t lastTs = 0; uint64_t lastTs = 0;
while (m_IsRunning) while (m_IsRunning.load(std::memory_order_acquire))
{ {
try try
{ {

View file

@ -10,6 +10,7 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <atomic>
#include "Queue.h" #include "Queue.h"
#include "Crypto.h" #include "Crypto.h"
#include "TunnelConfig.h" #include "TunnelConfig.h"
@ -99,20 +100,20 @@ namespace tunnel
std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; } std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const;
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
TunnelState GetState () const { return m_State; }; TunnelState GetState () const { return m_State; }
void SetState (TunnelState state); void SetState (TunnelState state);
bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsEstablished () const { return m_State == eTunnelStateEstablished; }
bool IsFailed () const { return m_State == eTunnelStateFailed; }; bool IsFailed () const { return m_State == eTunnelStateFailed; }
bool IsRecreated () const { return m_IsRecreated; }; bool IsRecreated () const { return m_IsRecreated; }
void SetIsRecreated () { m_IsRecreated = true; }; void SetIsRecreated () { m_IsRecreated = true; }
virtual bool IsInbound() const = 0; virtual bool IsInbound() const = 0;
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; }; std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; }
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; }; void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; }
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
virtual void Print (std::stringstream&) const {}; virtual void Print (std::stringstream&) const {}
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
@ -145,12 +146,12 @@ namespace tunnel
public: public:
OutboundTunnel (std::shared_ptr<const TunnelConfig> config): OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }; const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
// implements TunnelBase // implements TunnelBase
@ -169,14 +170,14 @@ namespace tunnel
{ {
public: public:
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {}; InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {}
void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg); void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
bool IsInbound() const { return true; } bool IsInbound() const { return true; }
// override TunnelBase // override TunnelBase
void Cleanup () { m_Endpoint.Cleanup (); }; void Cleanup () { m_Endpoint.Cleanup (); }
private: private:
@ -190,7 +191,7 @@ namespace tunnel
ZeroHopsInboundTunnel (); ZeroHopsInboundTunnel ();
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }
private: private:
@ -204,7 +205,7 @@ namespace tunnel
ZeroHopsOutboundTunnel (); ZeroHopsOutboundTunnel ();
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; }
private: private:
@ -224,7 +225,7 @@ namespace tunnel
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID); std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (); std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (); std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; }; std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; }
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID); std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
int GetTransitTunnelsExpirationTimeout (); int GetTransitTunnelsExpirationTimeout ();
void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel); void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
@ -266,7 +267,7 @@ namespace tunnel
private: private:
bool m_IsRunning; std::atomic_bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
@ -285,15 +286,15 @@ namespace tunnel
public: public:
// for HTTP only // for HTTP only
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; }; const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; }
size_t CountTransitTunnels() const; size_t CountTransitTunnels() const;
size_t CountInboundTunnels() const; size_t CountInboundTunnels() const;
size_t CountOutboundTunnels() const; size_t CountOutboundTunnels() const;
int GetQueueSize () { return m_Queue.GetSize (); }; int GetQueueSize () { return m_Queue.GetSize (); }
int GetTunnelCreationSuccessRate () const // in percents int GetTunnelCreationSuccessRate () const // in percents
{ {
int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations; int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;

View file

@ -8,6 +8,7 @@
#include "Destination.h" #include "Destination.h"
#include "Streaming.h" #include "Streaming.h"
#include <functional> #include <functional>
#include <atomic>
#include <websocketpp/config/asio_no_tls.hpp> #include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp> #include <websocketpp/server.hpp>
@ -100,35 +101,41 @@ namespace client
void Start() void Start()
{ {
if(m_Run) return; // already started if (!m_Run.load())
m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port); {
m_Server.start_accept(); m_Run.store(true);
m_Run = true; m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port);
m_Thread = new std::thread([&] (){ m_Server.start_accept();
while(m_Run) { m_Run = true;
m_Thread = new std::thread([&] (){
while (m_Run.load(std::memory_order_acquire)) {
try { try {
m_Server.run(); m_Server.run();
} catch( std::exception & ex) { } catch( std::exception & ex) {
LogPrint(eLogError, "Websocks runtime exception: ", ex.what()); LogPrint(eLogError, "Websocks runtime exception: ", ex.what());
} }
} }
}); });
m_Dest->Start(); m_Dest->Start();
}
} }
void Stop() void Stop()
{ {
for(const auto & conn : m_Conns) if (m_Run.load())
conn->Close(); {
for(const auto & conn : m_Conns)
conn->Close();
m_Dest->Stop(); m_Dest->Stop();
m_Run = false; m_Run.store(false);
m_Server.stop(); m_Server.stop();
if(m_Thread) { if(m_Thread) {
m_Thread->join(); m_Thread->join();
delete m_Thread; delete m_Thread;
}
m_Thread = nullptr;
} }
m_Thread = nullptr;
} }
boost::asio::ip::tcp::endpoint GetLocalEndpoint() boost::asio::ip::tcp::endpoint GetLocalEndpoint()
@ -140,7 +147,7 @@ namespace client
private: private:
std::vector<WebSocksConn_ptr> m_Conns; std::vector<WebSocksConn_ptr> m_Conns;
bool m_Run; std::atomic_bool m_Run;
ServerImpl m_Server; ServerImpl m_Server;
std::string m_Addr; std::string m_Addr;
int m_Port; int m_Port;

View file

@ -30,7 +30,7 @@ namespace i2p
public: public:
WebsocketServerImpl(const std::string & addr, int port) : WebsocketServerImpl(const std::string & addr, int port) :
m_run(false), m_IsRunning(false),
m_ws_thread(nullptr), m_ws_thread(nullptr),
m_ev_thread(nullptr), m_ev_thread(nullptr),
m_WebsocketTicker(m_Service) m_WebsocketTicker(m_Service)
@ -48,10 +48,12 @@ namespace i2p
} }
void Start() { void Start() {
m_run = true; if (!m_IsRunning.load())
m_server.start_accept(); {
m_ws_thread = new std::thread([&] () { m_IsRunning.store(true);
while(m_run) { m_server.start_accept();
m_ws_thread = new std::thread([&] () {
while(m_IsRunning.load(std::memory_order_acquire)) {
try { try {
m_server.run(); m_server.run();
} catch (std::exception & e ) { } catch (std::exception & e ) {
@ -59,8 +61,8 @@ namespace i2p
} }
} }
}); });
m_ev_thread = new std::thread([&] () { m_ev_thread = new std::thread([&] () {
while(m_run) { while(m_IsRunning.load(std::memory_order_acquire)) {
try { try {
m_Service.run(); m_Service.run();
break; break;
@ -69,25 +71,29 @@ namespace i2p
} }
} }
}); });
ScheduleTick(); ScheduleTick();
}
} }
void Stop() { void Stop() {
m_run = false; if (m_IsRunning.load())
m_Service.stop(); {
m_server.stop(); m_IsRunning.store(false);
m_Service.stop();
m_server.stop();
if(m_ev_thread) { if(m_ev_thread) {
m_ev_thread->join(); m_ev_thread->join();
delete m_ev_thread; delete m_ev_thread;
} }
m_ev_thread = nullptr; m_ev_thread = nullptr;
if(m_ws_thread) { if(m_ws_thread) {
m_ws_thread->join(); m_ws_thread->join();
delete m_ws_thread; delete m_ws_thread;
}
m_ws_thread = nullptr;
} }
m_ws_thread = nullptr;
} }
void ConnOpened(ServerConn c) void ConnOpened(ServerConn c)
@ -158,7 +164,7 @@ namespace i2p
private: private:
typedef std::set<ServerConn, std::owner_less<ServerConn> > ConnList; typedef std::set<ServerConn, std::owner_less<ServerConn> > ConnList;
bool m_run; std::atomic_bool m_IsRunning;
std::thread * m_ws_thread; std::thread * m_ws_thread;
std::thread * m_ev_thread; std::thread * m_ev_thread;
std::mutex m_connsMutex; std::mutex m_connsMutex;