diff --git a/README.md b/README.md index 4f86abab..876ea6fd 100644 --- a/README.md +++ b/README.md @@ -246,12 +246,10 @@ Your build directory should now look like this: * ... ## Running the server -If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo. -To give `AuthServer` network permissions and not require sudo, run the following command +If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you have to give the `AuthServer` binary network permissions by running the following command: ```bash sudo setcap 'cap_net_bind_service=+ep' AuthServer ``` -and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0. ### Linux Service If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server. diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 741a6e59..362dd431 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -27,7 +27,6 @@ #include "Game.h" #include "Server.h" - namespace Game { Logger* logger = nullptr; dServer* server = nullptr; diff --git a/dAuthServer/CMakeLists.txt b/dAuthServer/CMakeLists.txt index 7dcbf041..37799b8e 100644 --- a/dAuthServer/CMakeLists.txt +++ b/dAuthServer/CMakeLists.txt @@ -1,7 +1,4 @@ add_executable(AuthServer "AuthServer.cpp") - target_link_libraries(AuthServer ${COMMON_LIBRARIES} dServer) - target_include_directories(AuthServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer) - add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") diff --git a/dMasterServer/Start.cpp b/dMasterServer/Start.cpp index d35392f1..119092a4 100644 --- a/dMasterServer/Start.cpp +++ b/dMasterServer/Start.cpp @@ -4,68 +4,146 @@ #include "Game.h" #include "BinaryPathFinder.h" -void StartChatServer() { +#ifdef _WIN32 +#include +#include +#include + +namespace { + const auto startup = STARTUPINFOW{ + .cb = sizeof(STARTUPINFOW), + .lpReserved = nullptr, + .lpDesktop = nullptr, + .lpTitle = nullptr, + .dwX = 0, + .dwY = 0, + .dwXSize = 0, + .dwYSize = 0, + .dwXCountChars = 0, + .dwYCountChars = 0, + .dwFillAttribute = 0, + .dwFlags = 0, + .wShowWindow = 0, + .cbReserved2 = 0, + .lpReserved2 = nullptr, + .hStdInput = INVALID_HANDLE_VALUE, + .hStdOutput = INVALID_HANDLE_VALUE, + .hStdError = INVALID_HANDLE_VALUE, + }; +} +#else +#include +#endif + +uint32_t StartChatServer() { if (Game::ShouldShutdown()) { LOG("Currently shutting down. Chat will not be restarted."); - return; + return 0; + } + auto chat_path = BinaryPathFinder::GetBinaryDir() / "ChatServer"; +#ifdef _WIN32 + chat_path.replace_extension(".exe"); + auto chat_startup = startup; + auto chat_info = PROCESS_INFORMATION{}; + if (!CreateProcessW(chat_path.wstring().data(), chat_path.wstring().data(), + nullptr, nullptr, false, 0, nullptr, nullptr, + &chat_startup, &chat_info)) + { + LOG("Failed to launch ChatServer"); + return 0; + } + + // get pid and close unused handles + auto chat_pid = chat_info.dwProcessId; + CloseHandle(chat_info.hProcess); + CloseHandle(chat_info.hThread); +#else // *nix systems + const auto chat_pid = fork(); + if (chat_pid < 0) { + LOG("Failed to launch ChatServer"); + return 0; + } else if (chat_pid == 0) { + // We are the child process + execl(chat_path.string().c_str(), chat_path.string().c_str(), nullptr); } -#ifdef __APPLE__ - //macOS doesn't need sudo to run on ports < 1024 - auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); -#elif _WIN32 - auto result = system(("start /B " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); -#else - if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); - } else { - auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); -} #endif + LOG("ChatServer PID is %d", chat_pid); + return chat_pid; } -void StartAuthServer() { +uint32_t StartAuthServer() { if (Game::ShouldShutdown()) { LOG("Currently shutting down. Auth will not be restarted."); - return; + return 0; } -#ifdef __APPLE__ - auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); -#elif _WIN32 - auto result = system(("start /B " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); -#else - if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); - } else { - auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); -} -#endif -} - -void StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID) { + auto auth_path = BinaryPathFinder::GetBinaryDir() / "AuthServer"; #ifdef _WIN32 - std::string cmd = "start /B " + (BinaryPathFinder::GetBinaryDir() / "WorldServer.exe").string() + " -zone "; -#else - std::string cmd; - if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) { - cmd = "sudo " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; - } else { - cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; + auth_path.replace_extension(".exe"); + auto auth_startup = startup; + auto auth_info = PROCESS_INFORMATION{}; + if (!CreateProcessW(auth_path.wstring().data(), auth_path.wstring().data(), + nullptr, nullptr, false, 0, nullptr, nullptr, + &auth_startup, &auth_info)) + { + LOG("Failed to launch AuthServer"); + return 0; + } + + // get pid and close unused handles + auto auth_pid = auth_info.dwProcessId; + CloseHandle(auth_info.hProcess); + CloseHandle(auth_info.hThread); +#else // *nix systems + const auto auth_pid = fork(); + if (auth_pid < 0) { + LOG("Failed to launch AuthServer"); + return 0; + } else if (auth_pid == 0) { + // We are the child process + execl(auth_path.string().c_str(), auth_path.string().c_str(), nullptr); } #endif - - cmd.append(std::to_string(mapID)); - cmd.append(" -port "); - cmd.append(std::to_string(port)); - cmd.append(" -instance "); - cmd.append(std::to_string(lastInstanceID)); - cmd.append(" -maxclients "); - cmd.append(std::to_string(maxPlayers)); - cmd.append(" -clone "); - cmd.append(std::to_string(cloneID)); - -#ifndef _WIN32 - cmd.append("&"); //Sends our next process to the background on Linux -#endif - - auto ret = system(cmd.c_str()); + LOG("AuthServer PID is %d", auth_pid); + return auth_pid; +} + +uint32_t StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID) { + auto world_path = BinaryPathFinder::GetBinaryDir() / "WorldServer"; +#ifdef _WIN32 + world_path.replace_extension(".exe"); + auto cmd = world_path.wstring() + L" -zone " + std::to_wstring(mapID) + L" -port " + std::to_wstring(port) + + L" -instance " + std::to_wstring(lastInstanceID) + L" -maxclients " + std::to_wstring(maxPlayers) + + L" -clone " + std::to_wstring(cloneID); + + auto world_startup = startup; + auto world_info = PROCESS_INFORMATION{}; + if (!CreateProcessW(world_path.wstring().data(), cmd.data(), + nullptr, nullptr, false, 0, nullptr, nullptr, + &world_startup, &world_info)) + { + LOG("Failed to launch WorldServer"); + return 0; + } + + // get pid and close unused handles + auto world_pid = world_info.dwProcessId; + CloseHandle(world_info.hProcess); + CloseHandle(world_info.hThread); +#else + const auto world_pid = fork(); + if (world_pid < 0) { + LOG("Failed to launch WorldServer"); + return 0; + } else if (world_pid == 0) { + // We are the child process + execl(world_path.string().c_str(), world_path.string().c_str(), + "-zone", std::to_string(mapID).c_str(), + "-port", std::to_string(port).c_str(), + "-instance", std::to_string(lastInstanceID).c_str(), + "-maxclients", std::to_string(maxPlayers).c_str(), + "-clone", std::to_string(cloneID).c_str(), nullptr); + } +#endif + LOG("WorldServer PID is %d", world_pid); + return world_pid; } diff --git a/dMasterServer/Start.h b/dMasterServer/Start.h index 98c83233..85041f6e 100644 --- a/dMasterServer/Start.h +++ b/dMasterServer/Start.h @@ -1,6 +1,6 @@ #pragma once #include "dCommonVars.h" -void StartAuthServer(); -void StartChatServer(); -void StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID); +uint32_t StartAuthServer(); +uint32_t StartChatServer(); +uint32_t StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID); diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 20a21d49..c7e4b226 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -10,6 +10,7 @@ #include "MessageType/Server.h" #include "MessageType/Master.h" +#include "BinaryPathFinder.h" #include "BitStreamUtils.h" #include "MasterPackets.h" #include "ZoneInstanceManager.h" @@ -68,7 +69,16 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect LOG("%s Server is listening on %s:%i with encryption: %i", StringifiedEnum::ToString(serverType).data(), ip.c_str(), port, int(useEncryption)); else LOG("%s Server is listening on %s:%i with encryption: %i, running zone %i / %i", StringifiedEnum::ToString(serverType).data(), ip.c_str(), port, int(useEncryption), zoneID, instanceID); - } else { LOG("FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; } + } else { + LOG("FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); +#ifdef DARKFLAME_PLATFORM_LINUX + if (mServerType == ServerType::Auth) { + const auto cwd = BinaryPathFinder::GetBinaryDir(); + LOG("Try running the following command before launching again:\n sudo setcap 'cap_net_bind_service=+ep' \"%s/AuthServer\"", cwd.string().c_str()); + } +#endif + return; + } mLogger->SetLogToConsole(prevLogSetting); @@ -109,20 +119,23 @@ Packet* dServer::ReceiveFromMaster() { if (packet) { if (packet->length < 1) { mMasterPeer->DeallocatePacket(packet); return nullptr; } - if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { + switch (packet->data[0]) { + case ID_DISCONNECTION_NOTIFICATION: + [[fallthrough]]; + case ID_CONNECTION_LOST: { LOG("Lost our connection to master, shutting DOWN!"); mMasterConnectionActive = false; - //ConnectToMaster(); //We'll just shut down now + // ConnectToMaster(); // We'll just shut down now + break; } - - if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) { + case ID_CONNECTION_REQUEST_ACCEPTED: { LOG("Established connection to master, zone (%i), instance (%i)", this->GetZoneID(), this->GetInstanceID()); mMasterConnectionActive = true; mMasterSystemAddress = packet->systemAddress; MasterPackets::SendServerInfo(this, packet); + break; } - - if (packet->data[0] == ID_USER_PACKET_ENUM) { + case ID_USER_PACKET_ENUM: { if (static_cast(packet->data[1]) == eConnectionType::MASTER) { switch (static_cast(packet->data[3])) { case MessageType::Master::REQUEST_ZONE_TRANSFER_RESPONSE: { @@ -133,12 +146,13 @@ Packet* dServer::ReceiveFromMaster() { *mShouldShutdown = -2; break; - //When we handle these packets in World instead dServer, we just return the packet's pointer. + // When we handle these packets in World instead dServer, we just return the packet's pointer. default: - return packet; } } + break; + } } mMasterPeer->DeallocatePacket(packet); diff --git a/resources/masterconfig.ini b/resources/masterconfig.ini index ab04af99..1f14cf8d 100644 --- a/resources/masterconfig.ini +++ b/resources/masterconfig.ini @@ -7,15 +7,5 @@ master_server_port=2000 # The port number to start world servers on. Will be incremented for each world world_port_start=3000 -# Use sudo when launching the auth server. -# Required by default if on Linux as auth runs on port 1001 -use_sudo_auth=1 - -# Use sudo when launching the chat server -use_sudo_chat=0 - -# Use sudo when launching world servers -use_sudo_world=0 - # 0 or 1, should autostart auth, chat, and char servers prestart_servers=1