aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Main.cpp130
-rw-r--r--src/server/game/Server/WorldSocket.cpp6
-rw-r--r--src/server/game/Server/WorldSocket.h3
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp18
-rw-r--r--src/server/game/Server/WorldSocketMgr.h6
-rw-r--r--src/server/shared/Networking/AsyncAcceptor.h30
-rw-r--r--src/server/shared/Networking/SocketMgr.h12
-rw-r--r--src/server/worldserver/Main.cpp243
8 files changed, 260 insertions, 188 deletions
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index 1669e0958b7..6e67a950343 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -62,23 +62,16 @@ char serviceDescription[] = "TrinityCore World of Warcraft emulator auth service
*/
int m_ServiceStatus = -1;
-boost::asio::deadline_timer* _serviceStatusWatchTimer;
-void ServiceStatusWatcher(boost::system::error_code const& error);
+void ServiceStatusWatcher(std::weak_ptr<boost::asio::deadline_timer> serviceStatusWatchTimerRef, std::weak_ptr<boost::asio::io_service> ioServiceRef, boost::system::error_code const& error);
#endif
bool StartDB();
void StopDB();
-void SignalHandler(const boost::system::error_code& error, int signalNumber);
-void KeepDatabaseAliveHandler(const boost::system::error_code& error);
-void BanExpiryHandler(boost::system::error_code const& error);
+void SignalHandler(std::weak_ptr<boost::asio::io_service> ioServiceRef, boost::system::error_code const& error, int signalNumber);
+void KeepDatabaseAliveHandler(std::weak_ptr<boost::asio::deadline_timer> dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error);
+void BanExpiryHandler(std::weak_ptr<boost::asio::deadline_timer> banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error);
variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService);
-boost::asio::io_service* _ioService;
-boost::asio::deadline_timer* _dbPingTimer;
-uint32 _dbPingInterval;
-boost::asio::deadline_timer* _banExpiryCheckTimer;
-uint32 _banExpiryCheckInterval;
-
int main(int argc, char** argv)
{
signal(SIGABRT, &Trinity::AbortHandler);
@@ -134,16 +127,18 @@ int main(int argc, char** argv)
if (!StartDB())
return 1;
- _ioService = new boost::asio::io_service();
+ std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
+
+ std::shared_ptr<boost::asio::io_service> ioService = std::make_shared<boost::asio::io_service>();
// Get the list of realms for the server
- sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
+ sRealmList->Initialize(*ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
+
+ std::shared_ptr<void> sRealmListHandle(nullptr, [](void*) { sRealmList->Close(); });
if (sRealmList->GetRealms().empty())
{
TC_LOG_ERROR("server.authserver", "No valid realms specified.");
- StopDB();
- delete _ioService;
return 1;
}
@@ -152,65 +147,63 @@ int main(int argc, char** argv)
if (port < 0 || port > 0xFFFF)
{
TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
- StopDB();
- delete _ioService;
return 1;
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- sAuthSocketMgr.StartNetwork(*_ioService, bindIp, port);
+ if (!sAuthSocketMgr.StartNetwork(*ioService, bindIp, port))
+ {
+ TC_LOG_ERROR("server.authserver", "Failed to initialize network");
+ return 1;
+ }
+
+ std::shared_ptr<void> sAuthSocketMgrHandle(nullptr, [](void*) { sAuthSocketMgr.StopNetwork(); });
// Set signal handlers
- boost::asio::signal_set signals(*_ioService, SIGINT, SIGTERM);
+ boost::asio::signal_set signals(*ioService, SIGINT, SIGTERM);
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
signals.add(SIGBREAK);
#endif
- signals.async_wait(SignalHandler);
+ signals.async_wait(std::bind(&SignalHandler, std::weak_ptr<boost::asio::io_service>(ioService), std::placeholders::_1, std::placeholders::_2));
// Set process priority according to configuration settings
SetProcessPriority("server.authserver");
// Enabled a timed callback for handling the database keep alive ping
- _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
- _dbPingTimer = new boost::asio::deadline_timer(*_ioService);
- _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
+ int32 dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
+ std::shared_ptr<boost::asio::deadline_timer> dbPingTimer = std::make_shared<boost::asio::deadline_timer>(*ioService);
+ dbPingTimer->expires_from_now(boost::posix_time::minutes(dbPingInterval));
+ dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, std::weak_ptr<boost::asio::deadline_timer>(dbPingTimer), dbPingInterval, std::placeholders::_1));
- _banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60);
- _banExpiryCheckTimer = new boost::asio::deadline_timer(*_ioService);
- _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval));
- _banExpiryCheckTimer->async_wait(BanExpiryHandler);
+ int32 banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60);
+ std::shared_ptr<boost::asio::deadline_timer> banExpiryCheckTimer = std::make_shared<boost::asio::deadline_timer>(*ioService);
+ banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(banExpiryCheckInterval));
+ banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, std::weak_ptr<boost::asio::deadline_timer>(banExpiryCheckTimer), banExpiryCheckInterval, std::placeholders::_1));
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
+ std::shared_ptr<boost::asio::deadline_timer> serviceStatusWatchTimer;
if (m_ServiceStatus != -1)
{
- _serviceStatusWatchTimer = new boost::asio::deadline_timer(*_ioService);
- _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
- _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ serviceStatusWatchTimer = std::make_shared<boost::asio::deadline_timer>(*ioService);
+ serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher,
+ std::weak_ptr<boost::asio::deadline_timer>(serviceStatusWatchTimer),
+ std::weak_ptr<boost::asio::io_service>(ioService),
+ std::placeholders::_1));
}
#endif
// Start the io service worker loop
- _ioService->run();
-
- _banExpiryCheckTimer->cancel();
- _dbPingTimer->cancel();
-
- sAuthSocketMgr.StopNetwork();
+ ioService->run();
- sRealmList->Close();
-
- // Close the Database Pool and library
- StopDB();
+ banExpiryCheckTimer->cancel();
+ dbPingTimer->cancel();
TC_LOG_INFO("server.authserver", "Halting process...");
signals.cancel();
- delete _banExpiryCheckTimer;
- delete _dbPingTimer;
- delete _ioService;
return 0;
}
@@ -241,50 +234,57 @@ void StopDB()
MySQL::Library_End();
}
-void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/)
+void SignalHandler(std::weak_ptr<boost::asio::io_service> ioServiceRef, boost::system::error_code const& error, int /*signalNumber*/)
{
if (!error)
- _ioService->stop();
+ if (std::shared_ptr<boost::asio::io_service> ioService = ioServiceRef.lock())
+ ioService->stop();
}
-void KeepDatabaseAliveHandler(const boost::system::error_code& error)
+void KeepDatabaseAliveHandler(std::weak_ptr<boost::asio::deadline_timer> dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error)
{
if (!error)
{
- TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
- LoginDatabase.KeepAlive();
+ if (std::shared_ptr<boost::asio::deadline_timer> dbPingTimer = dbPingTimerRef.lock())
+ {
+ TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
+ LoginDatabase.KeepAlive();
- _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
+ dbPingTimer->expires_from_now(boost::posix_time::minutes(dbPingInterval));
+ dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, dbPingTimerRef, dbPingInterval, std::placeholders::_1));
+ }
}
}
-void BanExpiryHandler(boost::system::error_code const& error)
+void BanExpiryHandler(std::weak_ptr<boost::asio::deadline_timer> banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error)
{
if (!error)
{
- LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
- LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
+ if (std::shared_ptr<boost::asio::deadline_timer> banExpiryCheckTimer = banExpiryCheckTimerRef.lock())
+ {
+ LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
+ LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
- _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval));
- _banExpiryCheckTimer->async_wait(BanExpiryHandler);
+ banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(banExpiryCheckInterval));
+ banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, banExpiryCheckTimerRef, banExpiryCheckInterval, std::placeholders::_1));
+ }
}
}
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
-void ServiceStatusWatcher(boost::system::error_code const& error)
+void ServiceStatusWatcher(std::weak_ptr<boost::asio::deadline_timer> serviceStatusWatchTimerRef, std::weak_ptr<boost::asio::io_service> ioServiceRef, boost::system::error_code const& error)
{
if (!error)
{
- if (m_ServiceStatus == 0)
- {
- _ioService->stop();
- delete _serviceStatusWatchTimer;
- }
- else
+ if (std::shared_ptr<boost::asio::io_service> ioService = ioServiceRef.lock())
{
- _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
- _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ if (m_ServiceStatus == 0)
+ ioService->stop();
+ else if (std::shared_ptr<boost::asio::deadline_timer> serviceStatusWatchTimer = serviceStatusWatchTimerRef.lock())
+ {
+ serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher, serviceStatusWatchTimerRef, ioServiceRef, std::placeholders::_1));
+ }
}
}
}
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index b22d87038ba..ae8b3fd0998 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -40,7 +40,7 @@ private:
using boost::asio::ip::tcp;
WorldSocket::WorldSocket(tcp::socket&& socket)
- : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false)
+ : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
{
_headerBuffer.Resize(sizeof(ClientPktHeader));
}
@@ -87,7 +87,7 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result)
bool WorldSocket::Update()
{
EncryptablePacket* queued;
- MessageBuffer buffer;
+ MessageBuffer buffer(_sendBufferSize);
while (_bufferQueue.Dequeue(queued))
{
ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
@@ -97,7 +97,7 @@ bool WorldSocket::Update()
if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength())
{
QueuePacket(std::move(buffer));
- buffer.Resize(4096);
+ buffer.Resize(_sendBufferSize);
}
if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength())
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index 36ce6528beb..e8ea99cdb88 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -67,6 +67,8 @@ public:
void SendPacket(WorldPacket const& packet);
+ void SetSendBufferSize(std::size_t sendBufferSize) { _sendBufferSize = sendBufferSize; }
+
protected:
void OnClose() override;
void ReadHandler() override;
@@ -110,6 +112,7 @@ private:
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;
MPSCQueue<EncryptablePacket> _bufferQueue;
+ std::size_t _sendBufferSize;
QueryCallbackProcessor _queryProcessor;
std::string _ipCountry;
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
index 6e6fd5cf99f..5c392f23669 100644
--- a/src/server/game/Server/WorldSocketMgr.cpp
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -34,6 +34,7 @@ class WorldSocketThread : public NetworkThread<WorldSocket>
public:
void SocketAdded(std::shared_ptr<WorldSocket> sock) override
{
+ sock->SetSendBufferSize(sWorldSocketMgr.GetApplicationSendBufferSize());
sScriptMgr->OnSocketOpen(sock);
}
@@ -43,7 +44,7 @@ public:
}
};
-WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m_SockOutUBuff(65536), _tcpNoDelay(true)
+WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSystemSendBufferSize(-1), _socketApplicationSendBufferSize(65536), _tcpNoDelay(true)
{
}
@@ -61,17 +62,18 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string
TC_LOG_DEBUG("misc", "Max allowed socket connections %d", max_connections);
// -1 means use default
- _socketSendBufferSize = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
+ _socketSystemSendBufferSize = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
- m_SockOutUBuff = sConfigMgr->GetIntDefault("Network.OutUBuff", 65536);
+ _socketApplicationSendBufferSize = sConfigMgr->GetIntDefault("Network.OutUBuff", 65536);
- if (m_SockOutUBuff <= 0)
+ if (_socketApplicationSendBufferSize <= 0)
{
TC_LOG_ERROR("misc", "Network.OutUBuff is wrong in your config file");
return false;
}
- BaseSocketMgr::StartNetwork(service, bindIp, port, threadCount);
+ if (!BaseSocketMgr::StartNetwork(service, bindIp, port, threadCount))
+ return false;
_acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this));
@@ -91,10 +93,10 @@ void WorldSocketMgr::StopNetwork()
void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
{
// set some options here
- if (_socketSendBufferSize >= 0)
+ if (_socketSystemSendBufferSize >= 0)
{
boost::system::error_code err;
- sock.set_option(boost::asio::socket_base::send_buffer_size(_socketSendBufferSize), err);
+ sock.set_option(boost::asio::socket_base::send_buffer_size(_socketSystemSendBufferSize), err);
if (err && err != boost::system::errc::not_supported)
{
TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen sock.set_option(boost::asio::socket_base::send_buffer_size) err = %s", err.message().c_str());
diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h
index a5aee344bf7..ce81acfea78 100644
--- a/src/server/game/Server/WorldSocketMgr.h
+++ b/src/server/game/Server/WorldSocketMgr.h
@@ -45,14 +45,16 @@ public:
void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) override;
+ std::size_t GetApplicationSendBufferSize() const { return _socketApplicationSendBufferSize; }
+
protected:
WorldSocketMgr();
NetworkThread<WorldSocket>* CreateThreads() const override;
private:
- int32 _socketSendBufferSize;
- int32 m_SockOutUBuff;
+ int32 _socketSystemSendBufferSize;
+ int32 _socketApplicationSendBufferSize;
bool _tcpNoDelay;
};
diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h
index 8a73e6e59fc..7c827ec4454 100644
--- a/src/server/shared/Networking/AsyncAcceptor.h
+++ b/src/server/shared/Networking/AsyncAcceptor.h
@@ -31,7 +31,7 @@ public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) :
- _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)),
+ _acceptor(ioService), _endpoint(boost::asio::ip::address::from_string(bindIp), port),
_socket(ioService), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this))
{
}
@@ -66,6 +66,33 @@ public:
});
}
+ bool Bind()
+ {
+ boost::system::error_code errorCode;
+ _acceptor.open(_endpoint.protocol(), errorCode);
+ if (errorCode)
+ {
+ TC_LOG_INFO("network", "Failed to open acceptor %s", errorCode.message().c_str());
+ return false;
+ }
+
+ _acceptor.bind(_endpoint, errorCode);
+ if (errorCode)
+ {
+ TC_LOG_INFO("network", "Could not bind to %s:%u %s", _endpoint.address().to_string().c_str(), _endpoint.port(), errorCode.message().c_str());
+ return false;
+ }
+
+ _acceptor.listen(boost::asio::socket_base::max_connections, errorCode);
+ if (errorCode)
+ {
+ TC_LOG_INFO("network", "Failed to start listening on %s:%u %s", _endpoint.address().to_string().c_str(), _endpoint.port(), errorCode.message().c_str());
+ return false;
+ }
+
+ return true;
+ }
+
void Close()
{
if (_closed.exchange(true))
@@ -81,6 +108,7 @@ private:
std::pair<tcp::socket*, uint32> DefeaultSocketFactory() { return std::make_pair(&_socket, 0); }
tcp::acceptor _acceptor;
+ tcp::endpoint _endpoint;
tcp::socket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h
index cb836c86db8..523f6794e68 100644
--- a/src/server/shared/Networking/SocketMgr.h
+++ b/src/server/shared/Networking/SocketMgr.h
@@ -39,9 +39,10 @@ public:
{
ASSERT(threadCount > 0);
+ AsyncAcceptor* acceptor = nullptr;
try
{
- _acceptor = new AsyncAcceptor(service, bindIp, port);
+ acceptor = new AsyncAcceptor(service, bindIp, port);
}
catch (boost::system::system_error const& err)
{
@@ -49,6 +50,13 @@ public:
return false;
}
+ if (!acceptor->Bind())
+ {
+ TC_LOG_ERROR("network", "StartNetwork failed to bind socket acceptor");
+ return false;
+ }
+
+ _acceptor = acceptor;
_threadCount = threadCount;
_threads = CreateThreads();
@@ -119,7 +127,7 @@ public:
}
protected:
- SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(1)
+ SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(0)
{
}
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index df8bc252939..21c30ec0fa1 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -77,22 +77,35 @@ char serviceDescription[] = "TrinityCore World of Warcraft emulator world servic
int m_ServiceStatus = -1;
#endif
-boost::asio::io_service _ioService;
-boost::asio::deadline_timer _freezeCheckTimer(_ioService);
-uint32 _worldLoopCounter(0);
-uint32 _lastChangeMsTime(0);
-uint32 _maxCoreStuckTimeInMs(0);
-
-void SignalHandler(const boost::system::error_code& error, int signalNumber);
-void FreezeDetectorHandler(const boost::system::error_code& error);
+class FreezeDetector
+{
+ public:
+ FreezeDetector(boost::asio::io_service& ioService, uint32 maxCoreStuckTime)
+ : _timer(ioService), _worldLoopCounter(0), _lastChangeMsTime(0), _maxCoreStuckTimeInMs(maxCoreStuckTime) { }
+
+ static void Start(std::shared_ptr<FreezeDetector> const& freezeDetector)
+ {
+ freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(5));
+ freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, std::weak_ptr<FreezeDetector>(freezeDetector), std::placeholders::_1));
+ }
+
+ static void Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error);
+
+ private:
+ boost::asio::deadline_timer _timer;
+ uint32 _worldLoopCounter;
+ uint32 _lastChangeMsTime;
+ uint32 _maxCoreStuckTimeInMs;
+};
+
+void SignalHandler(boost::system::error_code const& error, int signalNumber);
AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService);
bool StartDB();
void StopDB();
void WorldUpdateLoop();
void ClearOnlineAccounts();
void ShutdownCLIThread(std::thread* cliThread);
-void ShutdownThreadPool(std::vector<std::thread>& threadPool);
-bool LoadRealmInfo();
+bool LoadRealmInfo(boost::asio::io_service& ioService);
variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& cfg_service);
/// Launch the Trinity server
@@ -126,9 +139,11 @@ extern int main(int argc, char** argv)
return 1;
}
+ std::shared_ptr<boost::asio::io_service> ioService = std::make_shared<boost::asio::io_service>();
+
sLog->RegisterAppender<AppenderDB>();
// If logs are supposed to be handled async then we need to pass the io_service into the Log singleton
- sLog->Initialize(sConfigMgr->GetBoolDefault("Log.Async.Enable", false) ? &_ioService : nullptr);
+ sLog->Initialize(sConfigMgr->GetBoolDefault("Log.Async.Enable", false) ? ioService.get() : nullptr);
TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", GitRevision::GetFullVersion());
TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n");
@@ -147,6 +162,8 @@ extern int main(int argc, char** argv)
OpenSSLCrypto::threadsSetup();
+ std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
+
// Seed the OpenSSL's PRNG here.
// That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login
BigNumber seed;
@@ -166,7 +183,7 @@ extern int main(int argc, char** argv)
}
// Set signal handlers (this must be done before starting io_service threads, because otherwise they would unblock and exit)
- boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
+ boost::asio::signal_set signals(*ioService, SIGINT, SIGTERM);
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
signals.add(SIGBREAK);
#endif
@@ -174,61 +191,83 @@ extern int main(int argc, char** argv)
// Start the Boost based thread pool
int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1);
- std::vector<std::thread> threadPool;
+ std::shared_ptr<std::vector<std::thread>> threadPool(new std::vector<std::thread>(), [ioService](std::vector<std::thread>* del)
+ {
+ ioService->stop();
+ for (std::thread& thr : *del)
+ thr.join();
+
+ delete del;
+ });
if (numThreads < 1)
numThreads = 1;
for (int i = 0; i < numThreads; ++i)
- threadPool.push_back(std::thread(boost::bind(&boost::asio::io_service::run, &_ioService)));
+ threadPool->push_back(std::thread([ioService]() { ioService->run(); }));
// Set process priority according to configuration settings
SetProcessPriority("server.worldserver");
// Start the databases
if (!StartDB())
- {
- ShutdownThreadPool(threadPool);
return 1;
- }
+
+ std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
// Set server offline (not connectable)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realm.Id.Realm);
- LoadRealmInfo();
+ LoadRealmInfo(*ioService);
- sMetric->Initialize(realm.Name, _ioService, []()
+ sMetric->Initialize(realm.Name, *ioService, []()
{
TC_METRIC_VALUE("online_players", sWorld->GetPlayerCount());
});
TC_METRIC_EVENT("events", "Worldserver started", "");
- // Initialize the World
+ std::shared_ptr<void> sMetricHandle(nullptr, [](void*)
+ {
+ TC_METRIC_EVENT("events", "Worldserver shutdown", "");
+ sMetric->ForceSend();
+ });
+
sScriptMgr->SetScriptLoader(AddScripts);
+ std::shared_ptr<void> sScriptMgrHandle(nullptr, [](void*)
+ {
+ sScriptMgr->Unload();
+ sScriptReloadMgr->Unload();
+ });
+
+ // Initialize the World
sWorld->SetInitialWorldSettings();
- // Launch CliRunnable thread
- std::thread* cliThread = nullptr;
-#ifdef _WIN32
- if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
-#else
- if (sConfigMgr->GetBoolDefault("Console.Enable", true))
-#endif
+ std::shared_ptr<void> mapManagementHandle(nullptr, [](void*)
{
- cliThread = new std::thread(CliThread);
- }
+ // unload battleground templates before different singletons destroyed
+ sBattlegroundMgr->DeleteAllBattlegrounds();
+
+ sInstanceSaveMgr->Unload();
+ sOutdoorPvPMgr->Die(); // unload it before MapManager
+ sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
+ });
// Start the Remote Access port (acceptor) if enabled
- AsyncAcceptor* raAcceptor = nullptr;
+ std::unique_ptr<AsyncAcceptor> raAcceptor;
if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
- raAcceptor = StartRaSocketAcceptor(_ioService);
+ raAcceptor.reset(StartRaSocketAcceptor(*ioService));
// Start soap serving thread if enabled
- std::thread* soapThread = nullptr;
+ std::shared_ptr<std::thread> soapThread;
if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
{
- soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878)));
+ soapThread.reset(new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))),
+ [](std::thread* thr)
+ {
+ thr->join();
+ delete thr;
+ });
}
// Launch the worldserver listener socket
@@ -243,7 +282,33 @@ extern int main(int argc, char** argv)
return 1;
}
- sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort, networkThreads);
+ if (!sWorldSocketMgr.StartNetwork(*ioService, worldListener, worldPort, networkThreads))
+ {
+ TC_LOG_ERROR("server.worldserver", "Failed to initialize network");
+ return 1;
+ }
+
+ std::shared_ptr<void> sWorldSocketMgrHandle(nullptr, [](void*)
+ {
+ sWorld->KickAll(); // save and kick all players
+ sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
+
+ sWorldSocketMgr.StopNetwork();
+
+ ///- Clean database before leaving
+ ClearOnlineAccounts();
+ });
+
+ // Launch CliRunnable thread
+ std::shared_ptr<std::thread> cliThread;
+#ifdef _WIN32
+ if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
+#else
+ if (sConfigMgr->GetBoolDefault("Console.Enable", true))
+#endif
+ {
+ cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
+ }
// Set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_OFFLINE, realm.Id.Realm);
@@ -251,11 +316,11 @@ extern int main(int argc, char** argv)
realm.Flags = RealmFlags(realm.Flags & ~uint32(REALM_FLAG_OFFLINE));
// Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec)
+ std::shared_ptr<FreezeDetector> freezeDetector;
if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0))
{
- _maxCoreStuckTimeInMs = coreStuckTime * 1000;
- _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(5));
- _freezeCheckTimer.async_wait(FreezeDetectorHandler);
+ freezeDetector = std::make_shared<FreezeDetector>(*ioService, coreStuckTime * 1000);
+ freezeDetector->Start(freezeDetector);
TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", coreStuckTime);
}
@@ -266,52 +331,17 @@ extern int main(int argc, char** argv)
WorldUpdateLoop();
// Shutdown starts here
- ShutdownThreadPool(threadPool);
+ threadPool.reset();
sLog->SetSynchronous();
sScriptMgr->OnShutdown();
- sWorld->KickAll(); // save and kick all players
- sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
-
- // unload battleground templates before different singletons destroyed
- sBattlegroundMgr->DeleteAllBattlegrounds();
-
- sWorldSocketMgr.StopNetwork();
-
- sInstanceSaveMgr->Unload();
- sOutdoorPvPMgr->Die();
- sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
- sScriptMgr->Unload();
- sScriptReloadMgr->Unload();
-
// set server offline
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realm.Id.Realm);
- // Clean up threads if any
- if (soapThread != nullptr)
- {
- soapThread->join();
- delete soapThread;
- }
-
- delete raAcceptor;
-
- ///- Clean database before leaving
- ClearOnlineAccounts();
-
- StopDB();
-
- TC_METRIC_EVENT("events", "Worldserver shutdown", "");
- sMetric->ForceSend();
-
TC_LOG_INFO("server.worldserver", "Halting process...");
- ShutdownCLIThread(cliThread);
-
- OpenSSLCrypto::threadsCleanup();
-
// 0 - normal shutdown
// 1 - shutdown at error
// 2 - restart command used, this code can be used by restarter for restart Trinityd
@@ -336,9 +366,10 @@ void ShutdownCLIThread(std::thread* cliThread)
if (!formatReturnCode)
errorBuffer = "Unknown error";
- TC_LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code %u, detail: %s",
- uint32(errorCode), errorBuffer);
- LocalFree(errorBuffer);
+ TC_LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code %u, detail: %s", uint32(errorCode), errorBuffer);
+
+ if (!formatReturnCode)
+ LocalFree(errorBuffer);
// send keyboard input to safely unblock the CLI thread
INPUT_RECORD b[4];
@@ -379,18 +410,6 @@ void ShutdownCLIThread(std::thread* cliThread)
}
}
-void ShutdownThreadPool(std::vector<std::thread>& threadPool)
-{
- sScriptMgr->OnNetworkStop();
-
- _ioService.stop();
-
- for (auto& thread : threadPool)
- {
- thread.join();
- }
-}
-
void WorldUpdateLoop()
{
uint32 realCurrTime = 0;
@@ -423,33 +442,36 @@ void WorldUpdateLoop()
}
}
-void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/)
+void SignalHandler(boost::system::error_code const& error, int /*signalNumber*/)
{
if (!error)
World::StopNow(SHUTDOWN_EXIT_CODE);
}
-void FreezeDetectorHandler(const boost::system::error_code& error)
+void FreezeDetector::Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error)
{
if (!error)
{
- uint32 curtime = getMSTime();
-
- uint32 worldLoopCounter = World::m_worldLoopCounter;
- if (_worldLoopCounter != worldLoopCounter)
- {
- _lastChangeMsTime = curtime;
- _worldLoopCounter = worldLoopCounter;
- }
- // possible freeze
- else if (getMSTimeDiff(_lastChangeMsTime, curtime) > _maxCoreStuckTimeInMs)
+ if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
{
- TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!");
- ABORT();
+ uint32 curtime = getMSTime();
+
+ uint32 worldLoopCounter = World::m_worldLoopCounter;
+ if (freezeDetector->_worldLoopCounter != worldLoopCounter)
+ {
+ freezeDetector->_lastChangeMsTime = curtime;
+ freezeDetector->_worldLoopCounter = worldLoopCounter;
+ }
+ // possible freeze
+ else if (getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime) > freezeDetector->_maxCoreStuckTimeInMs)
+ {
+ TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!");
+ ABORT();
+ }
+
+ freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(1));
+ freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, freezeDetectorRef, std::placeholders::_1));
}
-
- _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(1));
- _freezeCheckTimer.async_wait(FreezeDetectorHandler);
}
}
@@ -459,13 +481,20 @@ AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService)
std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
AsyncAcceptor* acceptor = new AsyncAcceptor(ioService, raListener, raPort);
+ if (!acceptor->Bind())
+ {
+ TC_LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
+ delete acceptor;
+ return nullptr;
+ }
+
acceptor->AsyncAccept<RASession>();
return acceptor;
}
-bool LoadRealmInfo()
+bool LoadRealmInfo(boost::asio::io_service& ioService)
{
- boost::asio::ip::tcp::resolver resolver(_ioService);
+ boost::asio::ip::tcp::resolver resolver(ioService);
boost::asio::ip::tcp::resolver::iterator end;
QueryResult result = LoginDatabase.PQuery("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE id = %u", realm.Id.Realm);