feat(Core): Linux: Support systemd socket activation for the worldserver game socket (#21998)

This commit is contained in:
Quentin Dawans
2025-11-29 21:53:48 +01:00
committed by GitHub
parent 77349fde48
commit dc8318cf6a
6 changed files with 144 additions and 20 deletions

View File

@@ -48,6 +48,7 @@
#include "SecretMgr.h"
#include "SharedDefines.h"
#include "SteadyTimer.h"
#include "Systemd.h"
#include "World.h"
#include "WorldSessionMgr.h"
#include "WorldSocket.h"
@@ -406,7 +407,8 @@ int main(int argc, char** argv)
sScriptMgr->OnShutdown();
// set server offline
LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
if (!sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false))
LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
LOG_INFO("server.worldserver", "Halting process...");

View File

@@ -397,6 +397,20 @@ Network.TcpNodelay = 1
Network.EnableProxyProtocol = 0
#
# Network.UseSocketActivation
# Description: Enable systemd socket activation support for the worldserver.
# When enabled and the process is started by systemd socket activation,
# the server will use the socket passed by systemd instead of
# creating and binding its own listening socket. Disabled by default.
#
# When enabled the realm is not automatically set as offline on shutdown.
#
# Example: 1 - (Enabled)
# Default: 0 - (Disabled)
Network.UseSocketActivation = 0
#
###################################################################################################

View File

@@ -20,6 +20,7 @@
#include "IpAddress.h"
#include "Log.h"
#include "Systemd.h"
#include <atomic>
#include <boost/asio/ip/tcp.hpp>
#include <functional>
@@ -33,10 +34,20 @@ class AsyncAcceptor
public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, bool supportSocketActivation = false) :
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
_socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); })
_socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); }),
_supportSocketActivation(supportSocketActivation)
{
int const listen_fd = get_listen_fd();
if (_supportSocketActivation && listen_fd > 0)
{
LOG_DEBUG("network", "Using socket from systemd socket activation");
boost::system::error_code errorCode;
_acceptor.assign(boost::asio::ip::tcp::v4(), listen_fd, errorCode);
if (errorCode)
LOG_WARN("network", "Failed to assign socket {}", errorCode.message());
}
}
template<class T>
@@ -72,27 +83,31 @@ public:
bool Bind()
{
boost::system::error_code errorCode;
_acceptor.open(_endpoint.protocol(), errorCode);
if (errorCode)
// with socket activation the acceptor is already open and bound
if (!_acceptor.is_open())
{
LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
return false;
}
_acceptor.open(_endpoint.protocol(), errorCode);
if (errorCode)
{
LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
return false;
}
#if AC_PLATFORM != AC_PLATFORM_WINDOWS
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
if (errorCode)
{
LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
return false;
}
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
if (errorCode)
{
LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
return false;
}
#endif
_acceptor.bind(_endpoint, errorCode);
if (errorCode)
{
LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
return false;
_acceptor.bind(_endpoint, errorCode);
if (errorCode)
{
LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
return false;
}
}
_acceptor.listen(ACORE_MAX_LISTEN_CONNECTIONS, errorCode);
@@ -124,6 +139,7 @@ private:
tcp::socket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
bool _supportSocketActivation;
};
template<class T>

View File

@@ -19,6 +19,7 @@
#define SocketMgr_h__
#include "AsyncAcceptor.h"
#include "Config.h"
#include "Errors.h"
#include "NetworkThread.h"
#include <boost/asio/ip/tcp.hpp>
@@ -42,7 +43,8 @@ public:
std::unique_ptr<AsyncAcceptor> acceptor;
try
{
acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port);
bool supportSocketActivation = sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false);
acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port, supportSocketActivation);
}
catch (boost::system::system_error const& err)
{