From 2bcd8a262c7bfb0fd8a6d086180f98051d959049 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Thu, 16 Jan 2014 20:06:39 -0700 Subject: [PATCH] Added TaskManager app --- engine/server/application/CMakeLists.txt | 1 + .../application/TaskManager/CMakeLists.txt | 6 + .../TaskManager/src/CMakeLists.txt | 116 ++ .../TaskManager/src/linux/ConsoleInput.cpp | 58 + .../src/linux/EnvironmentVariable.cpp | 39 + .../TaskManager/src/linux/ProcessSpawner.cpp | 167 +++ .../src/linux/TaskManagerSysInfo.cpp | 85 ++ .../TaskManager/src/linux/main.cpp | 45 + .../src/shared/CentralConnection.cpp | 115 ++ .../src/shared/CentralConnection.h | 42 + .../src/shared/ConfigTaskManager.cpp | 108 ++ .../src/shared/ConfigTaskManager.h | 273 ++++ .../TaskManager/src/shared/Console.cpp | 73 ++ .../TaskManager/src/shared/Console.h | 41 + .../src/shared/ConsoleConnection.cpp | 60 + .../src/shared/ConsoleConnection.h | 30 + .../src/shared/ConsoleImplementation.cpp | 50 + .../src/shared/ConsoleImplementation.h | 34 + .../src/shared/DatabaseConnection.cpp | 60 + .../src/shared/DatabaseConnection.h | 28 + .../src/shared/EnvironmentVariable.h | 10 + .../src/shared/FirstTaskManager.cpp | 12 + .../TaskManager/src/shared/FirstTaskManager.h | 18 + .../TaskManager/src/shared/GameConnection.cpp | 175 +++ .../TaskManager/src/shared/GameConnection.h | 43 + .../TaskManager/src/shared/Locator.cpp | 445 +++++++ .../TaskManager/src/shared/Locator.h | 46 + .../src/shared/ManagerConnection.cpp | 225 ++++ .../src/shared/ManagerConnection.h | 51 + .../src/shared/MetricsServerConnection.cpp | 87 ++ .../src/shared/MetricsServerConnection.h | 42 + .../src/shared/PlanetConnection.cpp | 65 + .../TaskManager/src/shared/PlanetConnection.h | 32 + .../TaskManager/src/shared/ProcessSpawner.h | 26 + .../TaskManager/src/shared/TaskConnection.cpp | 225 ++++ .../TaskManager/src/shared/TaskConnection.h | 75 ++ .../TaskManager/src/shared/TaskHandler.cpp | 41 + .../TaskManager/src/shared/TaskHandler.h | 33 + .../TaskManager/src/shared/TaskManager.cpp | 1135 +++++++++++++++++ .../TaskManager/src/shared/TaskManager.h | 179 +++ .../src/shared/TaskManagerSysInfo.h | 28 + .../TaskManager/src/win32/ConsoleInput.cpp | 22 + .../src/win32/EnvironmentVariable.cpp | 33 + .../TaskManager/src/win32/ProcessSpawner.cpp | 153 +++ .../src/win32/TaskManagerSysInfo.cpp | 147 +++ .../TaskManager/src/win32/WinMain.cpp | 43 + 46 files changed, 4822 insertions(+) create mode 100644 engine/server/application/TaskManager/CMakeLists.txt create mode 100644 engine/server/application/TaskManager/src/CMakeLists.txt create mode 100644 engine/server/application/TaskManager/src/linux/ConsoleInput.cpp create mode 100644 engine/server/application/TaskManager/src/linux/EnvironmentVariable.cpp create mode 100644 engine/server/application/TaskManager/src/linux/ProcessSpawner.cpp create mode 100644 engine/server/application/TaskManager/src/linux/TaskManagerSysInfo.cpp create mode 100644 engine/server/application/TaskManager/src/linux/main.cpp create mode 100644 engine/server/application/TaskManager/src/shared/CentralConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/CentralConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp create mode 100644 engine/server/application/TaskManager/src/shared/ConfigTaskManager.h create mode 100644 engine/server/application/TaskManager/src/shared/Console.cpp create mode 100644 engine/server/application/TaskManager/src/shared/Console.h create mode 100644 engine/server/application/TaskManager/src/shared/ConsoleConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/ConsoleConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/ConsoleImplementation.cpp create mode 100644 engine/server/application/TaskManager/src/shared/ConsoleImplementation.h create mode 100644 engine/server/application/TaskManager/src/shared/DatabaseConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/DatabaseConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/EnvironmentVariable.h create mode 100644 engine/server/application/TaskManager/src/shared/FirstTaskManager.cpp create mode 100644 engine/server/application/TaskManager/src/shared/FirstTaskManager.h create mode 100644 engine/server/application/TaskManager/src/shared/GameConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/GameConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/Locator.cpp create mode 100644 engine/server/application/TaskManager/src/shared/Locator.h create mode 100644 engine/server/application/TaskManager/src/shared/ManagerConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/ManagerConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/MetricsServerConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/MetricsServerConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/PlanetConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/PlanetConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/ProcessSpawner.h create mode 100644 engine/server/application/TaskManager/src/shared/TaskConnection.cpp create mode 100644 engine/server/application/TaskManager/src/shared/TaskConnection.h create mode 100644 engine/server/application/TaskManager/src/shared/TaskHandler.cpp create mode 100644 engine/server/application/TaskManager/src/shared/TaskHandler.h create mode 100644 engine/server/application/TaskManager/src/shared/TaskManager.cpp create mode 100644 engine/server/application/TaskManager/src/shared/TaskManager.h create mode 100644 engine/server/application/TaskManager/src/shared/TaskManagerSysInfo.h create mode 100644 engine/server/application/TaskManager/src/win32/ConsoleInput.cpp create mode 100644 engine/server/application/TaskManager/src/win32/EnvironmentVariable.cpp create mode 100644 engine/server/application/TaskManager/src/win32/ProcessSpawner.cpp create mode 100644 engine/server/application/TaskManager/src/win32/TaskManagerSysInfo.cpp create mode 100644 engine/server/application/TaskManager/src/win32/WinMain.cpp diff --git a/engine/server/application/CMakeLists.txt b/engine/server/application/CMakeLists.txt index b71b6369..9f743915 100644 --- a/engine/server/application/CMakeLists.txt +++ b/engine/server/application/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(LoginServer) +add_subdirectory(TaskManager) diff --git a/engine/server/application/TaskManager/CMakeLists.txt b/engine/server/application/TaskManager/CMakeLists.txt new file mode 100644 index 00000000..7a3c9684 --- /dev/null +++ b/engine/server/application/TaskManager/CMakeLists.txt @@ -0,0 +1,6 @@ + +cmake_minimum_required(VERSION 2.8) + +project(TaskManager) + +add_subdirectory(src) diff --git a/engine/server/application/TaskManager/src/CMakeLists.txt b/engine/server/application/TaskManager/src/CMakeLists.txt new file mode 100644 index 00000000..40572cc7 --- /dev/null +++ b/engine/server/application/TaskManager/src/CMakeLists.txt @@ -0,0 +1,116 @@ + +set(SHARED_SOURCES + shared/CentralConnection.cpp + shared/CentralConnection.h + shared/ConfigTaskManager.cpp + shared/ConfigTaskManager.h + shared/ConsoleConnection.cpp + shared/ConsoleConnection.h + shared/Console.cpp + shared/Console.h + shared/ConsoleImplementation.cpp + shared/ConsoleImplementation.h + shared/DatabaseConnection.cpp + shared/DatabaseConnection.h + shared/EnvironmentVariable.h + shared/FirstTaskManager.cpp + shared/FirstTaskManager.h + shared/GameConnection.cpp + shared/GameConnection.h + shared/Locator.cpp + shared/Locator.h + shared/ManagerConnection.cpp + shared/ManagerConnection.h + shared/MetricsServerConnection.cpp + shared/MetricsServerConnection.h + shared/PlanetConnection.cpp + shared/PlanetConnection.h + shared/ProcessSpawner.h + shared/TaskConnection.cpp + shared/TaskConnection.h + shared/TaskHandler.cpp + shared/TaskHandler.h + shared/TaskManager.cpp + shared/TaskManager.h + shared/TaskManagerSysInfo.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/ConsoleInput.cpp + win32/EnvironmentVariable.cpp + win32/ProcessSpawner.cpp + win32/TaskManagerSysInfo.cpp + win32/WinMain.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32) +else() + set(PLATFORM_SOURCES + linux/ConsoleInput.cpp + linux/EnvironmentVariable.cpp + linux/main.cpp + linux/ProcessSpawner.cpp + linux/TaskManagerSysInfo.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux) +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCompression/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include +) + +link_directories(${STLPORT_LIBDIR}) + +add_executable(TaskManager + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) + +target_link_libraries(TaskManager + sharedCompression + sharedDebug + sharedFile + sharedFoundation + sharedLog + sharedMath + sharedMemoryManager + sharedMessageDispatch + sharedNetwork + sharedNetworkMessages + sharedRandom + sharedSynchronization + sharedThread + sharedUtility + serverNetworkMessages + serverUtility + archive + fileInterface + localization + localizationArchive + unicode + unicodeArchive + udplibrary + ${ZLIB_LIBRARY} +) + +if(WIN32) + target_link_libraries(TaskManager mswsock ws2_32) +endif() diff --git a/engine/server/application/TaskManager/src/linux/ConsoleInput.cpp b/engine/server/application/TaskManager/src/linux/ConsoleInput.cpp new file mode 100644 index 00000000..a0d4580c --- /dev/null +++ b/engine/server/application/TaskManager/src/linux/ConsoleInput.cpp @@ -0,0 +1,58 @@ +// TaskManager.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "Console.h" +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------- + +struct SetBufferMode +{ + SetBufferMode(); + ~SetBufferMode() {}; +}; + +SetBufferMode::SetBufferMode() +{ + setvbuf(stdin, NULL, _IONBF, 0); +} + +//----------------------------------------------------------------------- + +const char Console::getNextChar() +{ + static SetBufferMode setBufferMode; + char result = 0; + fd_set rfds; + struct timeval tv; + + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + + tv.tv_sec = 0; + tv.tv_usec = 0; + + int ready = select(1, &rfds, 0, 0, &tv); + if(ready) + { + result = static_cast(getchar()); + if(result < 1) + result = 0; + } + /* + if(_kbhit()) + result = static_cast(_getche()); + */ + return result; +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/linux/EnvironmentVariable.cpp b/engine/server/application/TaskManager/src/linux/EnvironmentVariable.cpp new file mode 100644 index 00000000..66aa105f --- /dev/null +++ b/engine/server/application/TaskManager/src/linux/EnvironmentVariable.cpp @@ -0,0 +1,39 @@ + +#include "FirstTaskManager.h" + +#include +#include + +namespace EnvironmentVariable +{ + bool addToEnvironmentVariable(const char* key, const char* value) + { + bool retval = false; + const char* oldValue = getenv(key); + if (oldValue) + { + std::string s(oldValue); + s += ":"; + s += value; + + //Bad things happen if the first character happens to be : (ie from an empty environment string) + const char* newValue = s.c_str(); + if (newValue[0] == ':') + ++newValue; + + retval = (setenv(key, newValue, 1) == 0); + } + else + { + retval = (setenv(key, value, 0) == 0); + } + return retval; + } + + + bool setEnvironmentVariable(const char* key, const char* value) + { + return (setenv(key, value, 1) == 0); + } + +}; diff --git a/engine/server/application/TaskManager/src/linux/ProcessSpawner.cpp b/engine/server/application/TaskManager/src/linux/ProcessSpawner.cpp new file mode 100644 index 00000000..3996480b --- /dev/null +++ b/engine/server/application/TaskManager/src/linux/ProcessSpawner.cpp @@ -0,0 +1,167 @@ +#include "sharedFoundation/FirstSharedFoundation.h" +#include "ProcessSpawner.h" +#include +#include +#include +#include + +#include + +uint32 ProcessSpawner::prefix; +//----------------------------------------------------------------------- + +bool tokenize (const std::string & str, std::vector & result) +{ + size_t end_pos = 0; + size_t start_pos = 0; + + result.clear (); + + for (;;) + { + if (end_pos >= str.size ()) + break; + + start_pos = str.find_first_not_of (' ', end_pos); + + if (start_pos == str.npos) //lint !e1705 + break; + + //---------------------------------------------------------------------- + + if (str [start_pos] == '\"') + { + if (++start_pos >= str.size ()) + break; + end_pos = str.find_first_of ('\"', start_pos); + } + else + end_pos = str.find_first_of (' ', start_pos); + + //---------------------------------------------------------------------- + + if (start_pos == end_pos) + break; + + if (end_pos == str.npos) //lint !e1705 + { + result.push_back (str.substr (start_pos)); + break; + } + else + { + result.push_back (str.substr (start_pos, end_pos - start_pos)); + } + ++start_pos; + } + + return true; +} + +// ---------------------------------------------------------------------- + +uint32 execute(const char * commandLine, char * const * parameters) +{ + DEBUG_REPORT_LOG(true, ("Now Attempting To Spawn %s\n", commandLine)); + pid_t p; + // fork + p = fork(); + if (p == 0) + { + // i am child + DEBUG_REPORT_LOG(true, ("Now Spawning %s\n", commandLine)); + + int result = execv(commandLine, parameters); //lint !e10 Expecting a function (huh?) + if (result == -1) + { + IGNORE_RETURN(perror("execv")); //lint !e10 + _exit(0); + } + } + return p; //lint !e732 Loss of sign +} + +// ---------------------------------------------------------------------- + +void makeParameters(const std::vector & parameters, std::vector & p) +{ + std::vector::const_iterator i; + for(i = parameters.begin(); i != parameters.end(); ++i) + { + char * arg = new char[(*i).length() + 1]; + strcpy(arg, (*i).c_str()); //lint !e64 !e534 + p.push_back(arg); + } + p.push_back(NULL); +} + +// ---------------------------------------------------------------------- + +void freeParameters(std::vector & p) +{ + std::vector::iterator piter; + for(piter = p.begin(); piter != p.end(); ++piter) + { + char * arg = (*piter); + delete[] arg; + } +} + +// ---------------------------------------------------------------------- + +uint32 ProcessSpawner::execute(const std::string & commandLine, const std::vector & parameters) +{ + + std::vector p; + makeParameters(parameters, p); + + std::string c = "./"; + c += commandLine; + uint32 pid = ::execute(c.c_str(), &p[0]); + + freeParameters(p); + + return pid; +} + +// ---------------------------------------------------------------------- + +uint32 ProcessSpawner::execute(const std::string & commandLine) +{ + std::vector parameters; + IGNORE_RETURN(tokenize(commandLine, parameters)); + + std::vector p; + makeParameters(parameters, p); + + uint32 result = ::execute(p[0], &p[0]); + + freeParameters(p); + + return result; +} +// ---------------------------------------------------------------------- + +bool ProcessSpawner::isProcessActive(uint32 pid) +{ + pid_t result = waitpid(static_cast(pid), 0, WNOHANG|WUNTRACED); + return (result < 1); +} + +// ---------------------------------------------------------------------- + +void ProcessSpawner::kill(uint32 pid) +{ + IGNORE_RETURN(::kill(static_cast(pid), SIGKILL)); + int status; + IGNORE_RETURN(waitpid(static_cast(pid), &status, 0)); +} + +// ---------------------------------------------------------------------- + +void ProcessSpawner::forceCore(const unsigned long pid) +{ + IGNORE_RETURN(::kill(static_cast(pid), SIGABRT)); +} + +// ---------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/linux/TaskManagerSysInfo.cpp b/engine/server/application/TaskManager/src/linux/TaskManagerSysInfo.cpp new file mode 100644 index 00000000..31bc94bf --- /dev/null +++ b/engine/server/application/TaskManager/src/linux/TaskManagerSysInfo.cpp @@ -0,0 +1,85 @@ +// TaskManagerSysInfo.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "TaskManagerSysInfo.h" +#include + +#include "TaskManager.h" + +//----------------------------------------------------------------------- + +TaskManagerSysInfo::TaskManagerSysInfo() : +averageScore() +{ + update(); +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo::TaskManagerSysInfo(const TaskManagerSysInfo &) +{ + +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo::~TaskManagerSysInfo() +{ +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo & TaskManagerSysInfo::operator = (const TaskManagerSysInfo & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + } + return *this; +} + +//----------------------------------------------------------------------- + +const float TaskManagerSysInfo::getScore() const +{ +#if 0 + //Temporariy remove this since it's not giving us good results + FILE * avg = popen("uptime", "r"); + float a = 0.0f; + if(avg) + { + std::string output; + while(!feof(avg)) + { + char buf[1024] = {"\0"}; + + fread(buf, sizeof(buf), 1, avg); + output += buf; + } + char formatted[1024] = {"\0"}; + std::string load = output.substr(output.find("load average:")); + sscanf(load.c_str(), "load average: %f", &a); + pclose(avg); + } + return a; +#else + + float ret = static_cast(TaskManager::getNumGameConnections()); + return ret; + +#endif +} + +//----------------------------------------------------------------------- + +void TaskManagerSysInfo::update() +{ + +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/linux/main.cpp b/engine/server/application/TaskManager/src/linux/main.cpp new file mode 100644 index 00000000..9eb1a06f --- /dev/null +++ b/engine/server/application/TaskManager/src/linux/main.cpp @@ -0,0 +1,45 @@ +#include "sharedFoundation/FirstSharedFoundation.h" + +#include "ConfigTaskManager.h" +#include "TaskManager.h" + +#include "sharedCompression/SetupSharedCompression.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFile/SetupSharedFile.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "sharedRandom/SetupSharedRandom.h" +#include "sharedThread/SetupSharedThread.h" + +// ====================================================================== + +int main(int argc, char ** argv) +{ + SetupSharedThread::install(); + SetupSharedDebug::install(1024); + + //-- setup foundation + SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); + setupFoundationData.lpCmdLine = ConvertCommandLine(argc,argv); + setupFoundationData.configFile = "taskmanager.cfg"; + SetupSharedFoundation::install (setupFoundationData); + + SetupSharedCompression::install(); + SetupSharedFile::install(false); + SetupSharedNetworkMessages::install(); + SetupSharedRandom::install(static_cast(time(NULL))); //lint !e1924 !e64 // NULL is a C-Style cast? + + Os::setProgramName("TaskManager"); + //setup the server + ConfigTaskManager::install(); + + //-- run game + TaskManager::install(); + TaskManager::run(); + TaskManager::remove(); + SetupSharedFoundation::remove(); + + return 0; +} diff --git a/engine/server/application/TaskManager/src/shared/CentralConnection.cpp b/engine/server/application/TaskManager/src/shared/CentralConnection.cpp new file mode 100644 index 00000000..416b0af0 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/CentralConnection.cpp @@ -0,0 +1,115 @@ +// CentralConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "CentralConnection.h" +#include "TaskConnection.h" +#include "TaskManager.h" +#include "serverNetworkMessages/PreloadFinishedMessage.h" +#include "serverNetworkMessages/TaskSpawnProcess.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "sharedFoundation/Clock.h" +#include "sharedMessageDispatch/Transceiver.h" + +//----------------------------------------------------------------------- + +CentralConnection::CentralConnection(TaskConnection * c, const std::string & n) : +TaskHandler(), +callback(), +commandLine(n), +connected(true), +connection(c), +lastSpawnTime(Clock::timeMs()) +{ + callback.connect(c->getTransceiverClosed(), *this, &CentralConnection::closed); //lint !e1025 !e1703 !e1514 !e64 + callback.connect(*this, &CentralConnection::onProcessKilled); //lint !e1025 !e1703 !e1514 !e64 !e1058 !e118 +// TaskManager::startServer("ConnectionServer", ""); +// TaskManager::startServer("SwgDatabaseServer", ""); +} + +//----------------------------------------------------------------------- + +CentralConnection::~CentralConnection() +{ + connection = 0; +} + +//----------------------------------------------------------------------- + +void CentralConnection::closed(const Closed &) +{ + if(connected) + { + ProcessAborted a; + a.commandLine = commandLine; + a.hostName = NetworkHandler::getHostName(); + MessageDispatch::Transceiver b; + b.emitMessage(a); + + unsigned long t = Clock::timeMs(); + if(t - lastSpawnTime > 5000) // stop spawning if it bombs immediately + { + lastSpawnTime = t; + // need to restart it! + //IGNORE_RETURN(TaskManager::startServer(commandLine)); + } + else + { + // emit the killed message + ProcessKilled k; + k.commandLine = a.commandLine; + k.hostName = a.hostName; + MessageDispatch::Transceiver pk; + pk.emitMessage(k); + } + connected = false; + TaskManager::setCentralConnection(0); + } +} + +//----------------------------------------------------------------------- + +void CentralConnection::onProcessKilled(const ProcessKilled & k) +{ + if(k.commandLine == commandLine) + lastSpawnTime = Clock::timeMs(); // force it to stay dead +} + +//----------------------------------------------------------------------- + +void CentralConnection::receive(const Archive::ByteStream & message) +{ + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + + r = message.begin(); + if(m.isType("TaskSpawnProcess")) + { + TaskSpawnProcess s(r); + IGNORE_RETURN(TaskManager::startServer(s.getProcessName(), s.getOptions(), s.getTargetHostAddress(), s.getSpawnDelay())); + } + else if(m.isType("PreloadFinishedMessage")) + { + PreloadFinishedMessage m(r); + if (m.getFinished()) + TaskManager::onPreloadFinished(); + } + else if(m.isType("ConGenericMessage")) + { + ConGenericMessage taskConsoleCommand(r); + + static std::string command = taskConsoleCommand.getMsg(); + while(command.rfind(' ') != command.npos || command.rfind('\n') != command.npos || command.rfind('\r') != command.npos) + { + command = command.substr(0, command.length() - 1); + } + + TaskManager::executeCommand(command); + } +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/CentralConnection.h b/engine/server/application/TaskManager/src/shared/CentralConnection.h new file mode 100644 index 00000000..cfcd1300 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/CentralConnection.h @@ -0,0 +1,42 @@ +// CentralConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_CentralConnection_H +#define _INCLUDED_CentralConnection_H + +//----------------------------------------------------------------------- + +#include "sharedMessageDispatch/Transceiver.h" +#include "TaskHandler.h" + +class TaskConnection; +struct Closed; + +//----------------------------------------------------------------------- + +class CentralConnection : public TaskHandler +{ +public: + CentralConnection(TaskConnection * newConnection, const std::string & commandLine); + ~CentralConnection(); + + void closed(const Closed &); + void receive(const Archive::ByteStream & message); + +private: + CentralConnection & operator = (const CentralConnection & rhs); + CentralConnection(const CentralConnection & source); + void onProcessKilled(const struct ProcessKilled &); + +private: + MessageDispatch::Callback callback; + std::string commandLine; + bool connected; + TaskConnection * connection; + unsigned long lastSpawnTime; +}; //lint !e1712 default constructor not defined for class 'CentralConnection' + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_CentralConnection_H diff --git a/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp b/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp new file mode 100644 index 00000000..f961f6ef --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp @@ -0,0 +1,108 @@ +// ConfigTaskManager.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigTaskManager.h" + +#include + +//----------------------------------------------------------------------- + +ConfigTaskManager::Data * ConfigTaskManager::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("TaskManager", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("TaskManager", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("TaskManager", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("TaskManager", #a, b)) + +//----------------------------------------------------------------------- + +namespace ConfigTaskManagerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_environmentVariable; // ConfigFile owns the pointer +} + +using namespace ConfigTaskManagerNamespace; + +// ====================================================================== + +int ConfigTaskManager::getNumberOfEnvironmentVariables() +{ + return static_cast(ms_environmentVariable.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigTaskManager::getEnvironmentVariable(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfEnvironmentVariables()); + return ms_environmentVariable[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +void ConfigTaskManager::install(void) +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigTaskManager::Data; + + KEY_BOOL (autoStart, true); + KEY_STRING (clusterName, "devcluster"); + KEY_BOOL (verifyClusterName, false); + KEY_INT (gameServerTimeout, 600); + KEY_STRING (gameServiceBindInterface, ""); + KEY_INT (gameServicePort, 60001); + KEY_INT (consoleConnectionPort, 60000); + KEY_STRING (consoleServiceBindInterface, ""); + KEY_STRING (loginServerAddress, "swo-dev5.station.sony.com"); + KEY_INT (loginServerTaskServicePort, 44459); + KEY_FLOAT (maximumLoad, 3.0f); + KEY_FLOAT (loadConnectionServer, 0.5f); + KEY_FLOAT (loadPlanetServer, 0.128f); + KEY_FLOAT (loadGameServer, 1.0f); + KEY_BOOL (publishMode, false); + KEY_STRING (rcFileName, "taskmanager.rc"); + KEY_BOOL (restartCentral, false); + KEY_INT (restartDelayCentralServer, 60); // seconds + KEY_INT (restartDelayLogServer, 30); + KEY_INT (restartDelayMetricsServer, 60); + KEY_INT (restartDelayCommoditiesServer, 60); + KEY_INT (restartDelayTransferServer, 30); + KEY_STRING (taskManagerServiceBindInterface, ""); + KEY_INT (taskManagerServicePort, 50001); + KEY_INT (maximumClockDriftToleranceSeconds, 10); // seconds + KEY_INT (systemTimeCheckIntervalSeconds, 60); // seconds + KEY_INT (clockDriftFatalIntervalSeconds, 1*60*60); // seconds + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("TaskManager", "environmentVariable", index++, 0); + if (result != 0) + { + ms_environmentVariable.push_back(result); + } + } + while (result); +} + +//----------------------------------------------------------------------- + +void ConfigTaskManager::remove(void) +{ + delete data; + data = 0; +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/ConfigTaskManager.h b/engine/server/application/TaskManager/src/shared/ConfigTaskManager.h new file mode 100644 index 00000000..16a78225 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConfigTaskManager.h @@ -0,0 +1,273 @@ +// ConfigTaskManager.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _ConfigTaskManager_H +#define _ConfigTaskManager_H + +//----------------------------------------------------------------------- + +class ConfigTaskManager +{ + public: + struct Data + { + bool autoStart; + const char * clusterName; + bool verifyClusterName; + int consoleConnectionPort; + const char * consoleServiceBindInterface; + unsigned long gameServerTimeout; + const char * gameServiceBindInterface; + int gameServicePort; + const char * loginServerAddress; + int loginServerTaskServicePort; + float maximumLoad; + float loadConnectionServer; + float loadPlanetServer; + float loadGameServer; + bool publishMode; + const char * rcFileName; + bool restartCentral; + int restartDelayCentralServer; + int restartDelayLogServer; + int restartDelayMetricsServer; + int restartDelayCommoditiesServer; + int restartDelayTransferServer; + int taskManagerServicePort; + const char * taskManagerServiceBindInterface; + int maximumClockDriftToleranceSeconds; + int systemTimeCheckIntervalSeconds; + int clockDriftFatalIntervalSeconds; + }; + + static const bool getAutoStart (); + static const char * getClusterName (); + static const bool getVerifyClusterName (); + static const uint16 getConsoleConnectionPort (); + static const char * getConsoleServiceBindInterface (); + static const char * getLoginServerAddress (); + static const uint16 getLoginServerTaskServicePort (); + static const bool getPublishMode(); + static const char * getRcFileName (); + static bool getRestartCentral(); + static unsigned int getRestartDelayCentralServer (); + static unsigned int getRestartDelayLogServer (); + static unsigned int getRestartDelayMetricsServer (); + static unsigned int getRestartDelayCommoditiesServer (); + static unsigned int getRestartDelayTransferServer (); + static unsigned long getGameServerTimeout (); + static const char * getGameServiceBindInterface (); + static uint16 getGameServicePort(); + static float getMaximumLoad (); + static float getLoadConnectionServer (); + static float getLoadPlanetServer (); + static float getLoadGameServer (); + static uint16 getTaskManagerServicePort(); + static const char * getTaskManagerServiceBindInterface(); + static int getMaximumClockDriftToleranceSeconds(); + static int getSystemTimeCheckIntervalSeconds(); + static int getClockDriftFatalIntervalSeconds(); + + static void install (); + static void remove (); + + static int getNumberOfEnvironmentVariables(); + static char const * getEnvironmentVariable(int index); + +private: + static Data * data; +}; + +//----------------------------------------------------------------------- + +inline const bool ConfigTaskManager::getAutoStart() +{ + return data->autoStart; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getClusterName() +{ + return data->clusterName; +} + +//----------------------------------------------------------------------- + +inline const bool ConfigTaskManager::getVerifyClusterName() +{ + return data->verifyClusterName; +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigTaskManager::getConsoleConnectionPort() +{ + return static_cast(data->consoleConnectionPort); +} + +//----------------------------------------------------------------------- + +inline uint16 ConfigTaskManager::getGameServicePort() +{ + return static_cast(data->gameServicePort); +} + +//----------------------------------------------------------------------- + +inline uint16 ConfigTaskManager::getTaskManagerServicePort() +{ + return static_cast(data->taskManagerServicePort); +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getLoginServerAddress() +{ + return data->loginServerAddress; +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigTaskManager::getLoginServerTaskServicePort() +{ + return static_cast(data->loginServerTaskServicePort); +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getRcFileName() +{ + return data->rcFileName; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getConsoleServiceBindInterface() +{ + return data->consoleServiceBindInterface; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getGameServiceBindInterface() +{ + return data->gameServiceBindInterface; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigTaskManager::getTaskManagerServiceBindInterface() +{ + return data->taskManagerServiceBindInterface; +} + +//----------------------------------------------------------------------- + +inline const bool ConfigTaskManager::getPublishMode() +{ + return data->publishMode; +} + +//----------------------------------------------------------------------- + +inline float ConfigTaskManager::getMaximumLoad() +{ + return data->maximumLoad; +} + +//----------------------------------------------------------------------- + +inline float ConfigTaskManager::getLoadConnectionServer() +{ + return data->loadConnectionServer; +} + +//----------------------------------------------------------------------- + +inline float ConfigTaskManager::getLoadPlanetServer() +{ + return data->loadPlanetServer; +} + +//----------------------------------------------------------------------- + +inline float ConfigTaskManager::getLoadGameServer() +{ + return data->loadGameServer; +} + +// ---------------------------------------------------------------------- + +inline unsigned long ConfigTaskManager::getGameServerTimeout() +{ + return data->gameServerTimeout; +} + +// ---------------------------------------------------------------------- + +inline bool ConfigTaskManager::getRestartCentral() +{ + return data->restartCentral; +} + +// ---------------------------------------------------------------------- + +inline unsigned int ConfigTaskManager::getRestartDelayCentralServer() +{ + return static_cast(data->restartDelayCentralServer); +} + +// ---------------------------------------------------------------------- + +inline unsigned int ConfigTaskManager::getRestartDelayLogServer() +{ + return static_cast(data->restartDelayLogServer); +} + +// ---------------------------------------------------------------------- + +inline unsigned int ConfigTaskManager::getRestartDelayMetricsServer() +{ + return static_cast(data->restartDelayMetricsServer); +} + +// ---------------------------------------------------------------------- + +inline unsigned int ConfigTaskManager::getRestartDelayCommoditiesServer() +{ + return static_cast(data->restartDelayCommoditiesServer); +} + +// ---------------------------------------------------------------------- + +inline unsigned int ConfigTaskManager::getRestartDelayTransferServer() +{ + return static_cast(data->restartDelayTransferServer); +} + +// ---------------------------------------------------------------------- + +inline int ConfigTaskManager::getMaximumClockDriftToleranceSeconds() +{ + return data->maximumClockDriftToleranceSeconds; +} + +// ---------------------------------------------------------------------- + +inline int ConfigTaskManager::getSystemTimeCheckIntervalSeconds() +{ + return data->systemTimeCheckIntervalSeconds; +} + +// ---------------------------------------------------------------------- + +inline int ConfigTaskManager::getClockDriftFatalIntervalSeconds() +{ + return data->clockDriftFatalIntervalSeconds; +} + +// ---------------------------------------------------------------------- + +#endif // _ConfigTaskManager_H diff --git a/engine/server/application/TaskManager/src/shared/Console.cpp b/engine/server/application/TaskManager/src/shared/Console.cpp new file mode 100644 index 00000000..411a45fc --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/Console.cpp @@ -0,0 +1,73 @@ +// Console.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "ConfigTaskManager.h" +#include "Console.h" +#include "ConsoleImplementation.h" +#include + +//----------------------------------------------------------------------- + +Console::Console() : +consoleImplementation(new ConsoleImplementation) +{ +} + +//----------------------------------------------------------------------- + +Console::~Console() +{ + delete consoleImplementation; +} + +//----------------------------------------------------------------------- + +Console & Console::instance() +{ + static Console console; + return console; +} + +//----------------------------------------------------------------------- + +const std::string Console::getNextCommand() +{ + return instance().consoleImplementation->popNextCommand(); +} + +//----------------------------------------------------------------------- + +const bool Console::hasPendingCommand() +{ + return instance().consoleImplementation->hasPendingCommand(); +} + +//----------------------------------------------------------------------- + +void Console::update() +{ + if(ConfigTaskManager::getAutoStart()) + return; + + static Console & con = instance(); + + char ch = 0; + while((ch = con.getNextChar()) != 0) + { + if(ch == 10 || ch == 13) + { + con.consoleImplementation->pushCommand(con.currentCommand); + con.currentCommand.clear(); + } + else + { + con.currentCommand += ch; + } + } +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/shared/Console.h b/engine/server/application/TaskManager/src/shared/Console.h new file mode 100644 index 00000000..f97f5544 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/Console.h @@ -0,0 +1,41 @@ +// Console.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_Console_H +#define _INCLUDED_Console_H + +//----------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------- + +class ConsoleImplementation; + +//----------------------------------------------------------------------- + +class Console +{ +public: + ~Console(); + + static const bool hasPendingCommand (); + static const std::string getNextCommand (); + static void update (); + +private: + Console(); + Console & operator = (const Console & rhs); + Console(const Console & source); + + static Console & instance(); + const char getNextChar(); +private: + ConsoleImplementation * consoleImplementation; + std::string currentCommand; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_Console_H diff --git a/engine/server/application/TaskManager/src/shared/ConsoleConnection.cpp b/engine/server/application/TaskManager/src/shared/ConsoleConnection.cpp new file mode 100644 index 00000000..9c1fdc58 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConsoleConnection.cpp @@ -0,0 +1,60 @@ +// ConsoleConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "Archive/ByteStream.h" +#include "ConsoleConnection.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "TaskManager.h" + +//----------------------------------------------------------------------- + +ConsoleConnection::ConsoleConnection(UdpConnectionMT * udpConnection, TcpClient * t) : +ServerConnection(udpConnection, t) +{ +} + +//----------------------------------------------------------------------- + +ConsoleConnection::~ConsoleConnection() +{ +} + +//----------------------------------------------------------------------- + +void ConsoleConnection::onReceive(const Archive::ByteStream & message) +{ + static Archive::ReadIterator ri; + ri = message.begin(); + + GameNetworkMessage msg(ri); + if(msg.isType("ConGenericMessage")) + { + ri = message.begin(); + ConGenericMessage taskConsoleCommand(ri); + + static std::string command; + command = taskConsoleCommand.getMsg(); + while(command.rfind(' ') != command.npos || command.rfind('\n') != command.npos || command.rfind('\r') != command.npos) + command = command.substr(0, command.length() - 1); + + ConGenericMessage response(TaskManager::executeCommand(command), taskConsoleCommand.getMsgId()); + send(response, true); + + GameNetworkMessage dis("RequestDisconnect"); + send(dis, true); + + REPORT_LOG(true, ("Received remote console command from %s : [%s]\n", getRemoteAddress().c_str(), command.c_str())); + } + else + { + // someone is sending the wrong data! + disconnect(); + } +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/ConsoleConnection.h b/engine/server/application/TaskManager/src/shared/ConsoleConnection.h new file mode 100644 index 00000000..1970554e --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConsoleConnection.h @@ -0,0 +1,30 @@ +// ConsoleConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ConsoleConnection_H +#define _INCLUDED_ConsoleConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" + +//----------------------------------------------------------------------- + +class ConsoleConnection : public ServerConnection +{ +public: + ConsoleConnection(UdpConnectionMT * udpConnection, TcpClient *); + ~ConsoleConnection(); + + virtual void onReceive (const Archive::ByteStream & message); + +private: + ConsoleConnection & operator = (const ConsoleConnection & rhs); + ConsoleConnection(const ConsoleConnection & source); + +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ConsoleConnection_H diff --git a/engine/server/application/TaskManager/src/shared/ConsoleImplementation.cpp b/engine/server/application/TaskManager/src/shared/ConsoleImplementation.cpp new file mode 100644 index 00000000..2972b59b --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConsoleImplementation.cpp @@ -0,0 +1,50 @@ +// ConsoleImplementation.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "ConsoleImplementation.h" + +//----------------------------------------------------------------------- + +ConsoleImplementation::ConsoleImplementation() +{ +} + +//----------------------------------------------------------------------- + +ConsoleImplementation::~ConsoleImplementation() +{ +} + +//----------------------------------------------------------------------- + +const bool ConsoleImplementation::hasPendingCommand() const +{ + return (!m_pendingCommands.empty()); +} + +//----------------------------------------------------------------------- + +const std::string ConsoleImplementation::popNextCommand() +{ + std::string result; + if(hasPendingCommand()) + { + result = m_pendingCommands.front(); + m_pendingCommands.pop_front(); + } + return result; +} + +//----------------------------------------------------------------------- + +void ConsoleImplementation::pushCommand(const std::string & newCommand) +{ + m_pendingCommands.push_back(newCommand); +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/ConsoleImplementation.h b/engine/server/application/TaskManager/src/shared/ConsoleImplementation.h new file mode 100644 index 00000000..57f42fe5 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ConsoleImplementation.h @@ -0,0 +1,34 @@ +// ConsoleImplementation.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ConsoleImplementation_H +#define _INCLUDED_ConsoleImplementation_H + +//----------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------- + +class ConsoleImplementation +{ +public: + ConsoleImplementation(); + ~ConsoleImplementation(); + + const bool hasPendingCommand () const; + const std::string popNextCommand (); + void pushCommand (const std::string & newCommand); +private: + ConsoleImplementation & operator = (const ConsoleImplementation & rhs); + ConsoleImplementation(const ConsoleImplementation & source); + +private: + std::list m_pendingCommands; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ConsoleImplementation_H diff --git a/engine/server/application/TaskManager/src/shared/DatabaseConnection.cpp b/engine/server/application/TaskManager/src/shared/DatabaseConnection.cpp new file mode 100644 index 00000000..4eee169c --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/DatabaseConnection.cpp @@ -0,0 +1,60 @@ +// DatabaseConnection.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "DatabaseConnection.h" +#include "TaskManager.h" +#include "serverNetworkMessages/GameTaskManagerMessages.h" +#include "serverNetworkMessages/TaskSpawnProcess.h" + +//----------------------------------------------------------------------- + +DatabaseConnection::DatabaseConnection() : +TaskHandler() +{ +// TaskManager::startServer("PlanetServer", ""); +// TaskManager::startServer("SwgGameServer", ""); +} + +//----------------------------------------------------------------------- + +DatabaseConnection::~DatabaseConnection() +{ +} + +//----------------------------------------------------------------------- + +DatabaseConnection & DatabaseConnection::operator = (const DatabaseConnection & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + } + return *this; +} + +//----------------------------------------------------------------------- + +void DatabaseConnection::receive(const Archive::ByteStream & message) +{ + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + + r = message.begin(); + if(m.isType("TaskSpawnProcess")) + { + TaskSpawnProcess s(r); + IGNORE_RETURN(TaskManager::startServer(s.getProcessName(), s.getOptions(), s.getTargetHostAddress(), s.getSpawnDelay())); + } + else if(m.isType("ServerIdleMessage")) + { + ServerIdleMessage msg(r); + TaskManager::onDatabaseIdle(msg.getIsIdle()); + } +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/DatabaseConnection.h b/engine/server/application/TaskManager/src/shared/DatabaseConnection.h new file mode 100644 index 00000000..d7cb0256 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/DatabaseConnection.h @@ -0,0 +1,28 @@ +// DatabaseConnection.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_DatabaseConnection_H +#define _INCLUDED_DatabaseConnection_H + +//----------------------------------------------------------------------- + +#include "TaskHandler.h" +//----------------------------------------------------------------------- + +class DatabaseConnection : public TaskHandler +{ +public: + DatabaseConnection(); + ~DatabaseConnection(); + + void receive(const Archive::ByteStream & message); + +private: + DatabaseConnection & operator = (const DatabaseConnection & rhs); + DatabaseConnection(const DatabaseConnection & source); +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_DatabaseConnection_H diff --git a/engine/server/application/TaskManager/src/shared/EnvironmentVariable.h b/engine/server/application/TaskManager/src/shared/EnvironmentVariable.h new file mode 100644 index 00000000..f42a2589 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/EnvironmentVariable.h @@ -0,0 +1,10 @@ + + +namespace EnvironmentVariable +{ + //This function takes a string in the form key=value. It will add + //value to the environment variable key if key exists. Otherwise it + //will create a new env called key and set it to value. + bool addToEnvironmentVariable(const char* key, const char* value); + bool setEnvironmentVariable(const char* key, const char* value); +}; diff --git a/engine/server/application/TaskManager/src/shared/FirstTaskManager.cpp b/engine/server/application/TaskManager/src/shared/FirstTaskManager.cpp new file mode 100644 index 00000000..628e1e72 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/FirstTaskManager.cpp @@ -0,0 +1,12 @@ +// FirstTaskManager.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" + +void FirstTaskManagerFoo(){} //lint !e714 // enable #pragma warning disable + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/FirstTaskManager.h b/engine/server/application/TaskManager/src/shared/FirstTaskManager.h new file mode 100644 index 00000000..847b3e6f --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/FirstTaskManager.h @@ -0,0 +1,18 @@ +// FirstTaskManager.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_FirstTaskManager_H +#define _INCLUDED_FirstTaskManager_H + +//----------------------------------------------------------------------- +#pragma warning ( disable : 4786 ) + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundationTypes/FoundationTypes.h" +#include +#include + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_FirstTaskManager_H diff --git a/engine/server/application/TaskManager/src/shared/GameConnection.cpp b/engine/server/application/TaskManager/src/shared/GameConnection.cpp new file mode 100644 index 00000000..c0ea39e5 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/GameConnection.cpp @@ -0,0 +1,175 @@ +// GameConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "GameConnection.h" +#include "ConfigTaskManager.h" +#include "Archive/Archive.h" +#include "TaskManager.h" +#include "sharedFoundation/Clock.h" +#include "sharedLog/Log.h" +#include "sharedNetwork/NetworkHandler.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "ProcessSpawner.h" + +//----------------------------------------------------------------------- + +namespace GameConnectionNamespace +{ + std::vector s_gameConnections; +} + +using namespace GameConnectionNamespace; + +//----------------------------------------------------------------------- + +GameConnection::GameConnection(TaskConnection * c) : +TaskHandler(), +connection(c), +m_lastKeepalive(0), +m_pid(0), +m_commandLine(), +m_timeLastKilled(0), +m_loggedKill(false), +m_loggedKillForceCore(false) +{ + TaskManager::addToGameConnections(1); + s_gameConnections.push_back(this); +} + +//----------------------------------------------------------------------- + +GameConnection::~GameConnection() +{ + std::vector::iterator f = std::find(s_gameConnections.begin(), s_gameConnections.end(), this); + if(f != s_gameConnections.end()) + s_gameConnections.erase(f); + + connection = 0; + TaskManager::addToGameConnections(-1); +} + +//----------------------------------------------------------------------- + +void GameConnection::install() +{ +} + +//----------------------------------------------------------------------- + +void GameConnection::remove() +{ + s_gameConnections.clear(); +} + +//----------------------------------------------------------------------- + +void GameConnection::receive(const Archive::ByteStream & message) +{ + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + + r = message.begin(); + if(m.isType("GameServerTaskManagerKeepAlive")) + { + if(! m_pid) + { + GenericValueTypeMessage msg(r); + m_pid = msg.getValue(); + +#ifndef _WIN32 + // get the command line + if (m_pid && m_commandLine.empty()) + { + char filename[30]; + snprintf(filename, sizeof(filename)-1, "/proc/%lu/cmdline", m_pid); + + // format of the cmdline file is a NULL separates every + // parameter, so we'll have to replace the NULLs with spaces + FILE *inFile = fopen(filename,"rb"); + if (inFile) + { + char buffer[512]; + int bytesRead = fread(buffer, 1, sizeof(buffer)-1, inFile); + if ((bytesRead > 0) && (bytesRead < static_cast(sizeof(buffer)))) + { + buffer[bytesRead] = '\0'; + + for (int i = 0; i < bytesRead; ++i) + { + if (buffer[i] == '\0') + { + buffer[i] = ' '; + } + } + + m_commandLine = buffer; + } + + fclose(inFile); + } + } +#endif + } + m_lastKeepalive = Clock::timeSeconds(); + } +} + +//----------------------------------------------------------------------- + +void GameConnection::update() +{ + std::vector::iterator i; + std::vector v = s_gameConnections; + + const unsigned long currentTime = Clock::timeSeconds(); + const unsigned long gameServerTimeout = ConfigTaskManager::getGameServerTimeout(); + + if (gameServerTimeout > 0) + { + for (i = v.begin(); i != v.end(); ++i) + { + GameConnection * g = (*i); + if (g->m_lastKeepalive && g->m_pid && ((g->m_lastKeepalive + gameServerTimeout) < currentTime)) + { + // attempt ProcessSpawner::forceCore() once per minute and if that doesn't + // work after a period of gameServerTimeout, then do a ProcessSpawner::kill() + if ((currentTime - g->m_lastKeepalive) > (2 * gameServerTimeout)) + { + g->m_timeLastKilled = currentTime; + LOG("ServerHang", ("killing (kill) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + WARNING(true, ("killing (kill) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + + // one time logging to customer service channel + if (!g->m_loggedKill) + { + g->m_loggedKill = true; + LOG("TaskManager", ("ServerHang: killing (kill) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + } + + ProcessSpawner::kill(g->m_pid); + } + else if ((g->m_timeLastKilled == 0) || ((currentTime - g->m_timeLastKilled) >= 60)) + { + g->m_timeLastKilled = currentTime; + LOG("ServerHang", ("killing (forceCore) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + WARNING(true, ("killing (forceCore) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + + // one time logging to customer service channel + if (!g->m_loggedKillForceCore) + { + g->m_loggedKillForceCore = true; + LOG("TaskManager", ("ServerHang: killing (forceCore) GameServer %s,%d (%s) because it has not provided a keepalive message in %d seconds", NetworkHandler::getHumanReadableHostName().c_str(), g->m_pid, g->m_commandLine.c_str(), currentTime - g->m_lastKeepalive)); + } + + ProcessSpawner::forceCore(g->m_pid); + } + } + } + } +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/shared/GameConnection.h b/engine/server/application/TaskManager/src/shared/GameConnection.h new file mode 100644 index 00000000..14fadf2d --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/GameConnection.h @@ -0,0 +1,43 @@ +// GameConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_GameConnection_H +#define _INCLUDED_GameConnection_H + +//----------------------------------------------------------------------- + +#include "TaskHandler.h" + +#include + +class TaskConnection; + +//----------------------------------------------------------------------- + +class GameConnection : public TaskHandler +{ +public: + explicit GameConnection(TaskConnection * connection); + ~GameConnection(); + + static void install(); + void receive(const Archive::ByteStream & message); + static void remove(); + static void update(); + +private: + GameConnection & operator = (const GameConnection & rhs); + GameConnection(const GameConnection & source); + TaskConnection * connection; + unsigned long m_lastKeepalive; + unsigned long m_pid; + std::string m_commandLine; + unsigned long m_timeLastKilled; + bool m_loggedKill; + bool m_loggedKillForceCore; +}; //lint !e1712 + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_GameConnection_H diff --git a/engine/server/application/TaskManager/src/shared/Locator.cpp b/engine/server/application/TaskManager/src/shared/Locator.cpp new file mode 100644 index 00000000..994d2184 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/Locator.cpp @@ -0,0 +1,445 @@ +// ====================================================================== +// +// Locator.cpp +// +// Copyright 2000-04 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstTaskManager.h" +#include "Locator.h" + +#include "ConfigTaskManager.h" +#include "ManagerConnection.h" +#include "TaskManager.h" +#include "serverNetworkMessages/TaskUtilization.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedLog/Log.h" +#include +#include + +// ====================================================================== + +namespace LocatorNamespace +{ + float getConfigSetting(const char *section, const char *key, const float defaultValue) + { + const ConfigFile::Section * sec = ConfigFile::getSection(section); + if (sec == NULL) + return defaultValue; + + const ConfigFile::Key * ky = sec->findKey(key); + if (ky == NULL) + return defaultValue; + + return ky->getAsFloat(ky->getCount()-1, defaultValue); + } + + struct PreferredNode + { + std::string m_nodeLabel; + std::string m_processName; + std::vector m_nodeOptions; + + bool match(std::string const &processName, std::string const &options) const + { + if (m_processName != processName) + return false; + for (std::vector::const_iterator i = m_nodeOptions.begin(); i != m_nodeOptions.end(); ++i) + if (options.find(*i) == std::string::npos) + return false; + return true; + } + }; + + struct ServerEntry + { + ServerEntry(ManagerConnection *conn, std::string const &label, float load); + + bool operator==(std::string const &label) const + { + return m_label == label; + } + bool operator<(ServerEntry const & rhs) const + { + // don't change this; the code requires that the nodes + // list be ordered by the current load on the node + return m_load < rhs.m_load; + } + bool hasAvailableLoad(float cost) const + { + return ((m_load + cost) < m_maximumLoad); + } + + ManagerConnection *m_connection; + std::string m_label; + float m_load; + float m_maximumLoad; + }; + + ServerEntry::ServerEntry(ManagerConnection *conn, std::string const &label, float load) : + m_connection(conn), + m_label(label), + m_load(load), + m_maximumLoad(0.0f) + { + // see if there is a maximum load specified for this particular node + char key[128]; + snprintf(key, sizeof(key)-1, "maximumLoad.%s", m_label.c_str()); + key[sizeof(key)-1] = '\0'; + + m_maximumLoad = getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad()); + } + + std::vector s_serverList; + const char s_masterNodeLabel[] = "node0"; + float s_myLoad; + std::vector s_preferredNodes; + std::map s_closedConnections; // to keep track of TaskManager that we have lost connection to which has not yet reconnected + + ManagerConnection *getPreferredServer(std::string const &processName, std::string const &options, float cost); + ManagerConnection *getUnpreferredServer(float cost); + void addPreferredNode(std::string const &preferredNodeSpec); +} + +using namespace LocatorNamespace; + +// ====================================================================== + +void Locator::install() +{ + int index = 0; + char const * result = 0; + + do + { + result = ConfigFile::getKeyString("TaskManager", "preferredNode", index++, 0); + if (result) + addPreferredNode(result); + } + while (result); +} + +// ---------------------------------------------------------------------- + +void Locator::closed(std::string const &label, ManagerConnection const *oldConnection) +{ + if (oldConnection) + { + std::vector::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i != s_serverList.end()) + { + DEBUG_REPORT_LOG(true, ("Removing connection %s on %s from locator map\n", label.c_str(), oldConnection->getRemoteAddress().c_str())); + IGNORE_RETURN(s_serverList.erase(i)); + s_closedConnections[label] = oldConnection->getRemoteAddress(); + } + } +} + +// ---------------------------------------------------------------------- + +ManagerConnection *LocatorNamespace::getPreferredServer(std::string const &processName, std::string const &options, float cost) +{ + // Find a node other than the master node that can afford to run the process + // and is a preferred node for the process and option set. + for (std::vector::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i) + { + ServerEntry &e = *i; + if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost))) + { + for (std::vector::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j) + if ((*j).m_nodeLabel == e.m_label && (*j).match(processName, options)) + return e.m_connection; + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +ManagerConnection *LocatorNamespace::getUnpreferredServer(float cost) +{ + // Find a node other than the master node that can afford to run the process + // and is a not marked as a preferred node for anything; if more than one + // node qualifies, return the node with the lowest load + for (std::vector::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i) + { + ServerEntry &e = *i; + if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost))) + { + bool foundPreferred = false; + for (std::vector::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j) + { + if ((*j).m_nodeLabel == e.m_label) + { + foundPreferred = true; + break; + } + } + + // s_serverList is ordered by load, so this will + // return the available node with the lowest load + if (!foundPreferred) + return e.m_connection; + } + } + + return 0; +} + +// ---------------------------------------------------------------------- + +ManagerConnection *Locator::getBestServer(std::string const &processName, std::string const &options, float cost) +{ + if (s_serverList.empty()) + return 0; + + // first, look for a preferred node for this process + { + ManagerConnection * const connection = getPreferredServer(processName, options, cost); + if (connection) + return connection; + } + + // there is not a preferred node available, so look for a node which is not preferred in some form + { + ManagerConnection * const connection = getUnpreferredServer(cost); + if (connection) + return connection; + } + + // there is not a non-preferred node available, so look for any node other than the command node; + // If more than one node qualifies, we want to choose the one who currently has the lowest load + { + for (std::vector::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i) + { + ServerEntry &e = *i; + if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost))) + { + // s_serverList is ordered by load, so this will + // return the available node with the lowest load + return e.m_connection; + } + } + + WARNING(true, ("No hosts are available to spawn a process costing %f without exceeding the host's load limit", cost)); + } + + return 0; +} + +// ---------------------------------------------------------------------- + +ManagerConnection *Locator::getServer(std::string const &label) +{ + for (std::vector::const_iterator i = s_serverList.begin(); i != s_serverList.end(); ++i) + if (i->m_label == label || i->m_connection->getRemoteAddress() == label) + return i->m_connection; + + return 0; +} + +// ---------------------------------------------------------------------- + +float Locator::getServerLoad(std::string const &label) +{ + std::vector::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i != s_serverList.end()) + return i->m_load; + return 0.f; +} + +// ---------------------------------------------------------------------- + +float Locator::getServerMaximumLoad(std::string const &label) +{ + std::vector::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i != s_serverList.end()) + return i->m_maximumLoad; + + // see if there is a maximum load specified for this particular node + char key[128]; + snprintf(key, sizeof(key)-1, "maximumLoad.%s", label.c_str()); + key[sizeof(key)-1] = '\0'; + + return getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad()); +} + +// ---------------------------------------------------------------------- + +void Locator::incrementMyLoad(float amount) +{ + s_myLoad += amount; + std::sort(s_serverList.begin(), s_serverList.end()); +} + +// ---------------------------------------------------------------------- + +void Locator::decrementMyLoad(float amount) +{ + s_myLoad -= amount; + if (s_myLoad < 0.0f) + s_myLoad = 0.0f; + std::sort(s_serverList.begin(), s_serverList.end()); + updateAllLoads(-amount); +} + +// ---------------------------------------------------------------------- + +void Locator::incrementServerLoad(std::string const &label, float amount) +{ + std::vector::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i != s_serverList.end()) + { + i->m_load += amount; + std::sort(s_serverList.begin(), s_serverList.end()); + } +} + +// ---------------------------------------------------------------------- + +void Locator::decrementServerLoad(std::string const &label, float amount) +{ + std::vector::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i != s_serverList.end()) + { + i->m_load -= amount; + if (i->m_load < 0.0f) + { + DEBUG_WARNING(true, ("%s dropped less than 0", label.c_str())); + i->m_load = 0.0f; + } + std::sort(s_serverList.begin(), s_serverList.end()); + } +} + +// ---------------------------------------------------------------------- + +float Locator::getMyLoad() +{ + return s_myLoad; +} + +// ---------------------------------------------------------------------- + +float Locator::getMyMaximumLoad() +{ + static float myMaximumLoad = -1.0f; + + // get the maximum load for this particular node + if (myMaximumLoad <= 0.0f) + { + // see if there is a maximum load specified for this particular node + char key[128]; + snprintf(key, sizeof(key)-1, "maximumLoad.%s", TaskManager::getNodeLabel().c_str()); + key[sizeof(key)-1] = '\0'; + + myMaximumLoad = getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad()); + } + + return myMaximumLoad; +} + +// ---------------------------------------------------------------------- + +void Locator::opened(std::string const &label, ManagerConnection *newConnection) +{ + if (newConnection) + { + std::vector::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if (i == s_serverList.end()) + { + ServerEntry s(newConnection, label, 0.0f); + s_serverList.push_back(s); + std::sort(s_serverList.begin(), s_serverList.end()); + IGNORE_RETURN(s_closedConnections.erase(label)); + + LOG("TaskManagerConnect", ("Connection with remote task manager %s established with label %s, maximum load %f", newConnection->getRemoteAddress().c_str(), label.c_str(), s.m_maximumLoad)); + } + else + { + WARNING_STRICT_FATAL(true, ("Tried to add %s on %s to server list but it already exsists", label.c_str(), newConnection->getRemoteAddress().c_str())); + } + DEBUG_REPORT_LOG(true, ("Connection with remote task manager %s established with label %s\n", newConnection->getRemoteAddress().c_str(), label.c_str())); + TaskManager::runSpawnRequestQueue(); + } + else + WARNING_STRICT_FATAL(true, ("Passed null connection to Locator::opened")); +} + +// ---------------------------------------------------------------------- + +void Locator::updateServerLoad(std::string const &label, float load) +{ + std::vector::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label); + if(i != s_serverList.end()) + { + i->m_load += load; + std::sort(s_serverList.begin(), s_serverList.end()); + LOG("TaskManager", ("updateServerLoad(%s, %f)", label.c_str(), load)); + } + else + { + DEBUG_WARNING(true, ("Told to update load on %s which didn't exist\n", label.c_str())); + } + TaskManager::runSpawnRequestQueue(); +} + +// ---------------------------------------------------------------------- + +void Locator::updateAllLoads(float delta) +{ + if (!s_serverList.empty()) + { + TaskUtilization const util(TaskUtilization::SYSTEM_AVG, delta); + sendToAllTaskManagers(util); + } +} + +// ---------------------------------------------------------------------- + +std::map const & Locator::getClosedConnections() +{ + return s_closedConnections; +} + +// ---------------------------------------------------------------------- + +void Locator::sendToAllTaskManagers(GameNetworkMessage const &msg) +{ + if (!s_serverList.empty()) + for (std::vector::const_iterator i = s_serverList.begin(); i != s_serverList.end(); ++i) + i->m_connection->send(msg); +} + +// ---------------------------------------------------------------------- + +void LocatorNamespace::addPreferredNode(std::string const &preferredNodeSpec) +{ + // preferredNodeSpec is "nodeLabel:processName:option=value:option=value:..." + + PreferredNode n; + std::string::size_type lastPos = 0; + std::string::size_type pos; + + pos = preferredNodeSpec.find(':', lastPos); + n.m_nodeLabel = preferredNodeSpec.substr(lastPos, pos-lastPos); + lastPos = pos == std::string::npos ? preferredNodeSpec.size() : pos+1; + + pos = preferredNodeSpec.find(':', lastPos); + n.m_processName = preferredNodeSpec.substr(lastPos, pos-lastPos); + lastPos = pos == std::string::npos ? preferredNodeSpec.size() : pos+1; + + while (lastPos != std::string::npos) + { + pos = preferredNodeSpec.find(':', lastPos); + n.m_nodeOptions.push_back(preferredNodeSpec.substr(lastPos, pos-lastPos)); + lastPos = pos == std::string::npos ? std::string::npos : pos+1; + } + + if (!n.m_nodeLabel.empty() && !n.m_processName.empty()) + s_preferredNodes.push_back(n); +} + +// ====================================================================== + diff --git a/engine/server/application/TaskManager/src/shared/Locator.h b/engine/server/application/TaskManager/src/shared/Locator.h new file mode 100644 index 00000000..4f588b89 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/Locator.h @@ -0,0 +1,46 @@ +// ====================================================================== +// +// Locator.h +// +// Copyright 2000-04 Sony Online Entertainment +// +// ====================================================================== + +#ifndef _INCLUDED_Locator_H +#define _INCLUDED_Locator_H + +// ====================================================================== + +#include + +class GameNetworkMessage; +class ManagerConnection; + +// ====================================================================== + +class Locator +{ +public: + static void install(); + static void closed(std::string const &label, ManagerConnection const *oldConnection); + static ManagerConnection *getBestServer(std::string const &processName, std::string const &options, float cost); + static float getMyLoad(); + static float getMyMaximumLoad(); + static float getServerLoad(std::string const &label); + static float getServerMaximumLoad(std::string const &label); + static ManagerConnection *getServer(std::string const &label); + static void incrementMyLoad(float amount); + static void incrementServerLoad(std::string const &label, float amount); + static void decrementMyLoad(float amount); + static void decrementServerLoad(std::string const &label, float amount); + static void opened(std::string const &label, ManagerConnection *newConnection); + static void sendToAllTaskManagers(GameNetworkMessage const &msg); + static void updateServerLoad(std::string const &label, float load); + static void updateAllLoads(float delta); + static stdmap::fwd const & getClosedConnections(); +}; + +// ====================================================================== + +#endif // _INCLUDED_Locator_H + diff --git a/engine/server/application/TaskManager/src/shared/ManagerConnection.cpp b/engine/server/application/TaskManager/src/shared/ManagerConnection.cpp new file mode 100644 index 00000000..3720de92 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ManagerConnection.cpp @@ -0,0 +1,225 @@ +// ManagerConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "Locator.h" +#include "ManagerConnection.h" +#include "serverNetworkMessages/TaskProcessDiedMessage.h" +#include "serverNetworkMessages/TaskSpawnProcess.h" +#include "serverNetworkMessages/TaskSpawnProcessAck.h" +#include "serverNetworkMessages/TaskUtilization.h" +#include "serverNetworkMessages/TaskConnectionIdMessage.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/Scheduler.h" +#include "sharedLog/Log.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "ConfigTaskManager.h" +#include "TaskConnection.h" +#include "TaskManager.h" + +//----------------------------------------------------------------------- + +namespace ManagerConnectionNamespace +{ + int s_managerConnectionCount = 0; +} + +using namespace ManagerConnectionNamespace; + +//----------------------------------------------------------------------- + +ManagerConnection::ManagerConnection(const std::string & a, const unsigned short p) : +Connection(a,p, NetworkSetupData()), +m_nodeLabel(0), +m_remoteUtilAvg(100000.0f) +{ + +} + +//----------------------------------------------------------------------- +ManagerConnection::ManagerConnection(UdpConnectionMT * u, TcpClient * t) : +Connection(u, t), +m_nodeLabel(0), +m_remoteUtilAvg(100000.0f) +{ + +} + +//----------------------------------------------------------------------- + +ManagerConnection::~ManagerConnection() +{ + if (m_nodeLabel) + { + Locator::closed(*m_nodeLabel, this); + delete m_nodeLabel; + m_nodeLabel = 0; + } +} + +//----------------------------------------------------------------------- +void ManagerConnection::onConnectionClosed() +{ + DEBUG_REPORT_LOG(true, ("Manager connection %s closed\n", getRemoteAddress().c_str())); + TaskManager::retryConnection(this); + if (m_nodeLabel) + { + Locator::closed(*m_nodeLabel, this); + delete m_nodeLabel; + m_nodeLabel = 0; + } + s_managerConnectionCount--; +} + +//----------------------------------------------------------------------- + +void ManagerConnection::onConnectionOpened() +{ + DEBUG_REPORT_LOG(true, ("Manager connection opened\n")); + TaskConnectionIdMessage id(TaskConnectionIdMessage::TaskManager, TaskManager::getNodeLabel(), ConfigTaskManager::getClusterName()); + send(id); + s_managerConnectionCount++; +} + +//----------------------------------------------------------------------- + +void ManagerConnection::onReceive(const Archive::ByteStream & message) +{ + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + + r = message.begin(); + if (m.isType("SystemTimeCheck")) + { + long const currentTime = static_cast(::time(NULL)); + GenericValueTypeMessage > msg(r); + + if (TaskManager::getNodeLabel() == "node0") + { + if ((std::max(currentTime, msg.getValue().second) - std::min(currentTime, msg.getValue().second)) > ConfigTaskManager::getMaximumClockDriftToleranceSeconds()) + { + LOG("CustomerService", ("system_clock_mismatch:System clock mismatch (%d seconds) by more than %d seconds: master TaskManager epoch (%ld), remote TaskManager %s (%s) epoch (%ld)", (std::max(currentTime, msg.getValue().second) - std::min(currentTime, msg.getValue().second)), ConfigTaskManager::getMaximumClockDriftToleranceSeconds(), currentTime, msg.getValue().first.c_str(), getRemoteAddress().c_str(), msg.getValue().second)); + + // tell CentralServer about the system clock mismatch so it can report an alert to SOEMon + GenericValueTypeMessage systemTimeMismatchMessage("SystemTimeMismatchNotification", + FormattedString<1024>().sprintf("%s: %s (%s) is off by %ld seconds", CalendarTime::convertEpochToTimeStringLocal(static_cast(currentTime)).c_str(), msg.getValue().first.c_str(), getRemoteAddress().c_str(), (std::max(currentTime, msg.getValue().second) - std::min(currentTime, msg.getValue().second)))); + TaskManager::sendToCentralServer(systemTimeMismatchMessage); + } + } + } + else if (m.isType("TaskConnectionIdMessage")) + { + static long const clockDriftFatalTimePeriod = static_cast(TaskManager::getStartTime()) + ConfigTaskManager::getClockDriftFatalIntervalSeconds(); + long const currentTime = static_cast(::time(NULL)); + TaskConnectionIdMessage t(r); + WARNING_STRICT_FATAL(t.getServerType() != TaskConnectionIdMessage::TaskManager, + ("ManagerConnection received wrong type identifier")); + WARNING_STRICT_FATAL(m_nodeLabel, ("Received new taskconnectionIdMessage with an already named connection")); + + FATAL((ConfigTaskManager::getVerifyClusterName() && (TaskManager::getNodeLabel() == "node0") && (t.getServerType() == TaskConnectionIdMessage::TaskManager) && (t.getClusterName() != std::string(ConfigTaskManager::getClusterName()))), ("Remote TaskManager %s (%s) reported cluster name (%s) that is different from my cluster name (%s)", t.getCommandLine().c_str(), getRemoteAddress().c_str(), t.getClusterName().c_str(), ConfigTaskManager::getClusterName())); + + // don't allow cluster to start if the system clock across the boxes are out of sync + bool remoteSystemClockInSync = true; + if (TaskManager::getNodeLabel() == "node0") + { + if ((std::max(currentTime, t.getCurrentEpochTime()) - std::min(currentTime, t.getCurrentEpochTime())) > ConfigTaskManager::getMaximumClockDriftToleranceSeconds()) + { + remoteSystemClockInSync = false; + + // don't bring down the cluster if we lost a box and when the box is + // restarted, its system clock is out of sync; just ignore that + // TaskManager, and send it a message to terminate itself + if (currentTime <= clockDriftFatalTimePeriod) + { + FATAL(true, ("System clock mismatch (%d seconds) by more than %d seconds: master TaskManager epoch (%ld), remote TaskManager %s (%s) epoch (%ld)", (std::max(currentTime, t.getCurrentEpochTime()) - std::min(currentTime, t.getCurrentEpochTime())), ConfigTaskManager::getMaximumClockDriftToleranceSeconds(), currentTime, t.getCommandLine().c_str(), getRemoteAddress().c_str(), t.getCurrentEpochTime())); + } + else + { + LOG("CustomerService", ("system_clock_mismatch:System clock mismatch (%d seconds) by more than %d seconds: master TaskManager epoch (%ld), remote TaskManager %s (%s) epoch (%ld). Telling remote TaskManager to terminate.", (std::max(currentTime, t.getCurrentEpochTime()) - std::min(currentTime, t.getCurrentEpochTime())), ConfigTaskManager::getMaximumClockDriftToleranceSeconds(), currentTime, t.getCommandLine().c_str(), getRemoteAddress().c_str(), t.getCurrentEpochTime())); + + GenericValueTypeMessage > > systemTimeMismatchMessage("SystemTimeMismatchMessage", std::make_pair(TaskManager::getNodeLabel(), std::make_pair(static_cast(currentTime), t.getCurrentEpochTime()))); + send(systemTimeMismatchMessage); + } + } + } + + if (remoteSystemClockInSync) + { + m_nodeLabel = new std::string(t.getCommandLine()); + Locator::opened(*m_nodeLabel, this); + TaskManager::resendUnacknowledgedSpawnRequests(this, *m_nodeLabel); + } + } + else if (m.isType("SystemTimeMismatchMessage")) + { + GenericValueTypeMessage > > msg(r); + FATAL((msg.getValue().first == "node0"), ("System clock mismatch (%d seconds) by more than %d seconds: master TaskManager epoch (%ld), self epoch (%ld)", (std::max(msg.getValue().second.first, msg.getValue().second.second) - std::min(msg.getValue().second.first, msg.getValue().second.second)), ConfigTaskManager::getMaximumClockDriftToleranceSeconds(), msg.getValue().second.first, msg.getValue().second.second)); + } + else if(m.isType("TaskSpawnProcess")) + { + TaskSpawnProcess s(r); + if (TaskManager::startServer(s.getProcessName(), s.getOptions(), s.getTargetHostAddress(), s.getSpawnDelay()) == 0) + { + DEBUG_REPORT_LOG(true, ("Failed to spawn %s on this node\n", s.getProcessName().c_str())); + //send fail message back + } + else + { + TaskSpawnProcessAck ack(s.getTransactionId()); + send(ack); + } + } + else if(m.isType("TaskUtilization")) + { + TaskUtilization util(r); + switch(util.getUtilType()) + { + case TaskUtilization::SYSTEM_AVG: + { + if (m_nodeLabel) + { + m_remoteUtilAvg = util.getUtilAmount(); + Locator::updateServerLoad(*m_nodeLabel, m_remoteUtilAvg); + } + } + break; + default: + break; + } + } + else if(m.isType("TaskProcessDiedMessage")) + { + TaskProcessDiedMessage died(r); + TaskManager::sendToCentralServer(died); + } + else if(m.isType("TaskSpawnProcessAck")) + { + TaskSpawnProcessAck ack(r); + TaskManager::removePendingSpawnProcessAck(ack.getTransactionId()); + } +} + +//----------------------------------------------------------------------- + +void ManagerConnection::send(const GameNetworkMessage & message) +{ + Archive::ByteStream b; + message.pack(b); + Connection::send(b, true); +} + +//----------------------------------------------------------------------- + +int ManagerConnection::getConnectionCount() +{ + return s_managerConnectionCount; +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/shared/ManagerConnection.h b/engine/server/application/TaskManager/src/shared/ManagerConnection.h new file mode 100644 index 00000000..5c4922ca --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ManagerConnection.h @@ -0,0 +1,51 @@ +// ManagerConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ManagerConnection_H +#define _INCLUDED_ManagerConnection_H + +//----------------------------------------------------------------------- + +#include "sharedMessageDispatch/Transceiver.h" +#include "TaskHandler.h" +#include "sharedNetwork/Connection.h" + +class GameNetworkMessage; +class TaskConnection; + +//----------------------------------------------------------------------- + +class ManagerConnection : public Connection +{ +public: + ManagerConnection(const std::string & remoteAddres, const unsigned short remotePort); + ManagerConnection(UdpConnectionMT*, TcpClient *); + ~ManagerConnection(); + + static int getConnectionCount (); + const std::string* getNodeLabel() const; + virtual void onConnectionClosed (); + virtual void onConnectionOpened (); + virtual void onReceive (const Archive::ByteStream & message); + void send(const GameNetworkMessage & message); +private: + ManagerConnection & operator = (const ManagerConnection & rhs); + ManagerConnection(const ManagerConnection & source); + ManagerConnection(); + +private: + std::string *m_nodeLabel; + float m_remoteUtilAvg; +}; + +//----------------------------------------------------------------------- + +inline const std::string* ManagerConnection::getNodeLabel() const +{ + return m_nodeLabel; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ManagerConnection_H diff --git a/engine/server/application/TaskManager/src/shared/MetricsServerConnection.cpp b/engine/server/application/TaskManager/src/shared/MetricsServerConnection.cpp new file mode 100644 index 00000000..eeef0926 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/MetricsServerConnection.cpp @@ -0,0 +1,87 @@ +// MetricsServerConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "MetricsServerConnection.h" + +#include "sharedFoundation/Clock.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "TaskConnection.h" +#include "TaskManager.h" + +//----------------------------------------------------------------------- + +MetricsServerConnection::MetricsServerConnection(TaskConnection * c, const std::string & n) : +TaskHandler(), +callback(), +commandLine(n), +connected(true), +connection(c), +lastSpawnTime(Clock::timeMs()) +{ + callback.connect(c->getTransceiverClosed(), *this, &MetricsServerConnection::closed); //lint !e1025 !e1703 !e1514 !e64 + callback.connect(*this, &MetricsServerConnection::onProcessKilled); //lint !e1025 !e1703 !e1514 !e64 !e1058 !e118 +} + +//----------------------------------------------------------------------- + +MetricsServerConnection::~MetricsServerConnection() +{ + connection = 0; +} + +//----------------------------------------------------------------------- + +void MetricsServerConnection::closed(const Closed &) +{ + if(connected) + { + ProcessAborted a; + a.commandLine = commandLine; + a.hostName = NetworkHandler::getHostName(); + MessageDispatch::Transceiver b; + b.emitMessage(a); + + unsigned long t = Clock::timeMs(); + if(t - lastSpawnTime > 5000) // stop spawning if it bombs immediately + { + lastSpawnTime = t; + // need to restart it! +// IGNORE_RETURN(TaskManager::startServer("MetricsServer", "", "local")); + } + else + { + // emit the killed message + ProcessKilled k; + k.commandLine = a.commandLine; + k.hostName = a.hostName; + MessageDispatch::Transceiver pk; + pk.emitMessage(k); + } + connected = false; + } +} + +//----------------------------------------------------------------------- + +void MetricsServerConnection::onProcessKilled(const ProcessKilled & k) +{ + if(k.commandLine == commandLine) + lastSpawnTime = Clock::timeMs(); // force it to stay dead +} + +//----------------------------------------------------------------------- + +void MetricsServerConnection::receive(const Archive::ByteStream & ) +{ +#if 0 + Archive::ReadIterator r(message); + GameNetworkMessage m(r); +#endif +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/MetricsServerConnection.h b/engine/server/application/TaskManager/src/shared/MetricsServerConnection.h new file mode 100644 index 00000000..ebb3ef29 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/MetricsServerConnection.h @@ -0,0 +1,42 @@ +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_MetricsServerConnection_H +#define _INCLUDED_MetricsServerConnection_H + +//----------------------------------------------------------------------- + +#include "sharedMessageDispatch/Transceiver.h" +#include "TaskHandler.h" + +class TaskConnection; +struct Closed; + +//----------------------------------------------------------------------- + +class MetricsServerConnection : public TaskHandler +{ +public: + MetricsServerConnection(TaskConnection * newConnection, const std::string & commandLine); + ~MetricsServerConnection(); + + void closed(const Closed &); + void receive(const Archive::ByteStream & message); + +private: + MetricsServerConnection(); + MetricsServerConnection & operator = (const MetricsServerConnection & rhs); + MetricsServerConnection(const MetricsServerConnection & source); + void onProcessKilled(const struct ProcessKilled &); + +private: + MessageDispatch::Callback callback; + std::string commandLine; + bool connected; + TaskConnection * connection; + unsigned long lastSpawnTime; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_MetricsServerConnection_H diff --git a/engine/server/application/TaskManager/src/shared/PlanetConnection.cpp b/engine/server/application/TaskManager/src/shared/PlanetConnection.cpp new file mode 100644 index 00000000..216d7e0c --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/PlanetConnection.cpp @@ -0,0 +1,65 @@ +// PlanetConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. + + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "PlanetConnection.h" + +#include "serverNetworkMessages/TaskSpawnProcess.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "TaskConnection.h" +#include "TaskManager.h" + + +//----------------------------------------------------------------------- + +PlanetConnection::PlanetConnection(TaskConnection * c) : +TaskHandler(), +connection(c) +{ +} + +//----------------------------------------------------------------------- + +PlanetConnection::PlanetConnection(const PlanetConnection &) +{ + connection = 0; + +} + +//----------------------------------------------------------------------- + +PlanetConnection::~PlanetConnection() +{ +} + +//----------------------------------------------------------------------- + +PlanetConnection & PlanetConnection::operator = (const PlanetConnection & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + } + return *this; +} + +//----------------------------------------------------------------------- + +void PlanetConnection::receive(const Archive::ByteStream & message) +{ + static const std::string localName = NetworkHandler::getHostName(); + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + + r = message.begin(); + if(m.isType("TaskSpawnProcess")) + { + TaskSpawnProcess s(r); + TaskManager::startServer(s.getProcessName(), s.getOptions(), s.getTargetHostAddress(), s.getSpawnDelay()); + } +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/shared/PlanetConnection.h b/engine/server/application/TaskManager/src/shared/PlanetConnection.h new file mode 100644 index 00000000..7830ccbb --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/PlanetConnection.h @@ -0,0 +1,32 @@ +// PlanetConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. + + +#ifndef _INCLUDED_PlanetConnection_H +#define _INCLUDED_PlanetConnection_H + +//----------------------------------------------------------------------- + +#include "TaskHandler.h" + +class TaskConnection; + +//----------------------------------------------------------------------- + +class PlanetConnection : public TaskHandler +{ +public: + PlanetConnection(TaskConnection * connection); + ~PlanetConnection(); + + void receive(const Archive::ByteStream & message); + +private: + PlanetConnection & operator = (const PlanetConnection & rhs); + PlanetConnection(const PlanetConnection & source); + TaskConnection * connection; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_PlanetConnection_H diff --git a/engine/server/application/TaskManager/src/shared/ProcessSpawner.h b/engine/server/application/TaskManager/src/shared/ProcessSpawner.h new file mode 100644 index 00000000..afd94f5c --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/ProcessSpawner.h @@ -0,0 +1,26 @@ +#ifndef _PROCESS_SPAWNER_H +#define _PROCESS_SPAWNER_H + +#include +#include + +class ProcessSpawner +{ +public: + static uint32 execute(const std::string & commandLine, const std::vector & parameters); + static uint32 execute(const std::string & commandLine); + static void forceCore(const unsigned long pid); + static bool isProcessActive(uint32 pid); + static void kill(uint32 pid); + static uint32 postfixCounter; + static uint32 prefix; +private: + ProcessSpawner(); + ~ProcessSpawner(); + ProcessSpawner(const ProcessSpawner&); + ProcessSpawner& operator= (const ProcessSpawner&); +}; + +//----------------------------------------------------------------------- + +#endif // _PROCESS_SPAWNER_H diff --git a/engine/server/application/TaskManager/src/shared/TaskConnection.cpp b/engine/server/application/TaskManager/src/shared/TaskConnection.cpp new file mode 100644 index 00000000..522578f5 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskConnection.cpp @@ -0,0 +1,225 @@ +// TaskConnection.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- +#include "FirstTaskManager.h" + +#include "CentralConnection.h" +#include "ConfigTaskManager.h" +#include "DatabaseConnection.h" +#include "Locator.h" +#include "GameConnection.h" +#include "ManagerConnection.h" +#include "MetricsServerConnection.h" +#include "PlanetConnection.h" +#include "TaskConnection.h" +#include "TaskManager.h" +#include "serverNetworkMessages/ExcommunicateGameServerMessage.h" +#include "serverNetworkMessages/TaskConnectionIdMessage.h" +#include "serverNetworkMessages/TaskKillProcess.h" +#include "sharedNetwork/NetworkSetupData.h" + +//----------------------------------------------------------------------- + +TaskConnection::TaskConnection(const std::string & a, const unsigned short p) : +Connection(a, p, NetworkSetupData()), +closed(), +failed(), +identified(), +opened(), +overflowing(), +receiveMessage(), +reset(), +handler(0) +{ +} + +//----------------------------------------------------------------------- + +TaskConnection::TaskConnection(UdpConnectionMT * u, TcpClient * t) : +Connection(u, t), +closed(), +failed(), +identified(), +opened(), +overflowing(), +receiveMessage(), +reset(), +handler(0) +{ +} + +//----------------------------------------------------------------------- + +TaskConnection::~TaskConnection() +{ + delete handler; +} + +//----------------------------------------------------------------------- + +void TaskConnection::onConnectionClosed() +{ + static Closed msg; + closed.emitMessage(msg); //lint !e738 Symbol 'msg' not explicitly initialized +} + +//----------------------------------------------------------------------- + +void TaskConnection::onConnectionOpened() +{ + DEBUG_REPORT_LOG(true, ("Task Connection opened %s\n", getRemoteAddress().c_str())); + static Opened msg; + opened.emitMessage(msg); //lint !e738 Symbol 'msg' not explicitly initialized +} + +//----------------------------------------------------------------------- + +void TaskConnection::onConnectionOverflowing(const unsigned int bytesPending) +{ + static Overflowing msg; + msg.bytesPending = bytesPending; + overflowing.emitMessage(msg); +} + +//----------------------------------------------------------------------- + +void TaskConnection::onReceive(const Archive::ByteStream & message) +{ + static Receive msg; + + if(handler) + handler->receive(message); + + Archive::ReadIterator r(message); + GameNetworkMessage m(r); + if(m.isType("TaskConnectionIdMessage")) + { + r = message.begin(); + TaskConnectionIdMessage t(r); + + FATAL((ConfigTaskManager::getVerifyClusterName() && (TaskManager::getNodeLabel() == "node0") && (t.getServerType() == TaskConnectionIdMessage::TaskManager) && (t.getClusterName() != std::string(ConfigTaskManager::getClusterName()))), ("Remote TaskManager %s (%s) reported cluster name (%s) that is different from my cluster name (%s)", t.getCommandLine().c_str(), getRemoteAddress().c_str(), t.getClusterName().c_str(), ConfigTaskManager::getClusterName())); + + Identified i = {this, t.getServerType() }; + identified.emitMessage(i); + + switch(i.id) + { + case TaskConnectionIdMessage::Central: + { + REPORT_LOG(true, ("New Central Server connection active\n")); + handler = new CentralConnection(this, t.getCommandLine()); + TaskManager::setCentralConnection(this); + } + break; + case TaskConnectionIdMessage::Game: + { + REPORT_LOG(true, ("New Game Server connection active\n")); + handler = new GameConnection(this); + } + break; + case TaskConnectionIdMessage::Database: + { + REPORT_LOG(true, ("New Database Server connection active\n")); + handler = new DatabaseConnection(); + } + break; + case TaskConnectionIdMessage::Metrics: + { + REPORT_LOG(true, ("New Metrics Server connection active\n")); + handler = new MetricsServerConnection(this, t.getCommandLine()); + } + break; + case TaskConnectionIdMessage::Planet: + { + REPORT_LOG(true, ("New Planet Server connection active\n")); + handler = new PlanetConnection(this); + } + break; + + default: + WARNING_STRICT_FATAL(true, ("Unknown id (%d) received on task connection", i.id)); + break; + } + } + else if(m.isType("ExcommunicateGameServerMessage")) + { + r = message.begin(); + ExcommunicateGameServerMessage ex(r); + TaskKillProcess k(ex.getHostName(), ex.getProcessId(), true); + TaskManager::killProcess(k); + + // broadcast to other task managers + Locator::sendToAllTaskManagers(k); + } + else if(m.isType("TaskKillProcess")) + { + r = message.begin(); + TaskKillProcess k(r); + TaskManager::killProcess(k); + } + + msg.message = &message; + receiveMessage.emitMessage(msg); +} + +//----------------------------------------------------------------------- + +void TaskConnection::send(const GameNetworkMessage & message) +{ + Archive::ByteStream b; + message.pack(b); + Connection::send(b, true); +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverClosed() +{ + return closed; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverFailed() +{ + return failed; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverIdentified() +{ + return identified; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverOpened() +{ + return opened; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverOverflowing() +{ + return overflowing; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverReceive() +{ + return receiveMessage; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- + +MessageDispatch::Transceiver & TaskConnection::getTransceiverReset() +{ + return reset; //lint !e1536 Exposing low access member +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/TaskManager/src/shared/TaskConnection.h b/engine/server/application/TaskManager/src/shared/TaskConnection.h new file mode 100644 index 00000000..f427756c --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskConnection.h @@ -0,0 +1,75 @@ +// TaskConnection.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_TaskConnection_H +#define _INCLUDED_TaskConnection_H + +//----------------------------------------------------------------------- + +#include +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/Connection.h" + +namespace Archive +{ + class ByteStream; +} + +class GameNetworkMessage; +class TaskConnection; +class TaskHandler; + +//----------------------------------------------------------------------- +struct Closed {}; +struct Failed {}; +struct Identified {TaskConnection * connection; unsigned char id;}; +struct Opened {}; +struct Overflowing {unsigned int bytesPending;}; +struct Receive {const Archive::ByteStream * message;}; +struct Reset {}; + +class TaskConnection : public Connection +{ +public: + +public: + TaskConnection(const std::string & remoteAddress, const unsigned short remotePort); + TaskConnection(UdpConnectionMT *, TcpClient *); + ~TaskConnection(); + + static int getConnectionCount (); + virtual void onConnectionClosed (); + virtual void onConnectionOpened (); + virtual void onConnectionOverflowing (const unsigned int bytesPending); + virtual void onReceive (const Archive::ByteStream & message); + void send (const GameNetworkMessage & message); //lint !e1411 Member with different signature hides virtual member 'Connection::send(const Archive::ByteStream &, bool) const // jrandall how can it hide the virtual if the signature differs? + + MessageDispatch::Transceiver & getTransceiverClosed (); + MessageDispatch::Transceiver & getTransceiverFailed (); + MessageDispatch::Transceiver & getTransceiverIdentified (); + MessageDispatch::Transceiver & getTransceiverOpened (); + MessageDispatch::Transceiver & getTransceiverOverflowing (); + MessageDispatch::Transceiver & getTransceiverReceive (); + MessageDispatch::Transceiver & getTransceiverReset (); + +private: // capabilities / emissions + MessageDispatch::Transceiver closed; + MessageDispatch::Transceiver failed; + MessageDispatch::Transceiver identified; + MessageDispatch::Transceiver opened; + MessageDispatch::Transceiver overflowing; + MessageDispatch::Transceiver receiveMessage; + MessageDispatch::Transceiver reset; + +private: + TaskConnection & operator = (const TaskConnection & rhs); + TaskConnection(const TaskConnection & source); + +private: + TaskHandler * handler; +}; //lint !e1712 default constructor not defined for class 'TaskConnection' + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_TaskConnection_H diff --git a/engine/server/application/TaskManager/src/shared/TaskHandler.cpp b/engine/server/application/TaskManager/src/shared/TaskHandler.cpp new file mode 100644 index 00000000..537bd28c --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskHandler.cpp @@ -0,0 +1,41 @@ +// TaskHandler.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "TaskHandler.h" + +//----------------------------------------------------------------------- + +TaskHandler::TaskHandler() +{ +} + +//----------------------------------------------------------------------- + +TaskHandler::TaskHandler(const TaskHandler &) +{ + +} + +//----------------------------------------------------------------------- + +TaskHandler::~TaskHandler() +{ +} + +//----------------------------------------------------------------------- + +TaskHandler & TaskHandler::operator = (const TaskHandler & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + } + return *this; +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/shared/TaskHandler.h b/engine/server/application/TaskManager/src/shared/TaskHandler.h new file mode 100644 index 00000000..810b91af --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskHandler.h @@ -0,0 +1,33 @@ +// TaskHandler.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_TaskHandler_H +#define _INCLUDED_TaskHandler_H + +//----------------------------------------------------------------------- + +namespace Archive +{ + class ByteStream; +} + +//----------------------------------------------------------------------- + +class TaskHandler +{ +public: + TaskHandler(); + virtual ~TaskHandler() = 0; + + virtual void receive(const Archive::ByteStream & message) = 0; + +private: + TaskHandler & operator = (const TaskHandler & rhs); + TaskHandler(const TaskHandler & source); + +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_TaskHandler_H diff --git a/engine/server/application/TaskManager/src/shared/TaskManager.cpp b/engine/server/application/TaskManager/src/shared/TaskManager.cpp new file mode 100644 index 00000000..9a26204e --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskManager.cpp @@ -0,0 +1,1135 @@ +// TaskManager.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- +#include "FirstTaskManager.h" + +#include "CentralConnection.h" +#include "ConfigTaskManager.h" +#include "Console.h" +#include "ConsoleConnection.h" +#include "GameConnection.h" +#include "Locator.h" +#include "ManagerConnection.h" +#include "ProcessSpawner.h" +#include "serverNetworkMessages/SetConnectionServerPublic.h" +#include "serverNetworkMessages/TaskKillProcess.h" +#include "serverNetworkMessages/TaskProcessDiedMessage.h" +#include "serverNetworkMessages/TaskSpawnProcess.h" +#include "fileInterface/StdioFile.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedLog/Log.h" +#include "sharedLog/SetupSharedLog.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/Address.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "EnvironmentVariable.h" +#include "TaskConnection.h" +#include "TaskManager.h" +#include "TaskManagerSysInfo.h" + +namespace TaskManagerNameSpace +{ + std::vector ms_deferredSpawns; + + int ms_numGameConnections = 0; + bool ms_doUpdate=false; + TaskManager * gs_instance = 0; + + int ms_idleFrames = 0; + bool ms_preloadFinished = false; + bool ms_done = false; + + std::map s_processRestartDelayInformation; + + void initializeRestartDelayInformation() + { + s_processRestartDelayInformation["CentralServer"] = ConfigTaskManager::getRestartDelayCentralServer(); + s_processRestartDelayInformation["LogServer"] = ConfigTaskManager::getRestartDelayLogServer(); + s_processRestartDelayInformation["MetricsServer"] = ConfigTaskManager::getRestartDelayMetricsServer(); + s_processRestartDelayInformation["CommoditiesServer"] = ConfigTaskManager::getRestartDelayCommoditiesServer(); + s_processRestartDelayInformation["CommodityServer"] = ConfigTaskManager::getRestartDelayCommoditiesServer(); + s_processRestartDelayInformation["TransferServer"] = ConfigTaskManager::getRestartDelayTransferServer(); + } + + TaskManager::SpawnDelaySeconds getRestartDelayInformation(const std::string & name) + { + TaskManager::SpawnDelaySeconds result = 0; + + for (std::map::const_iterator i = s_processRestartDelayInformation.begin(); i != s_processRestartDelayInformation.end(); ++i) + { + if (name.find(i->first) != std::string::npos) + { + result = i->second; + break; + } + } + + return result; + } + + std::map s_processLoadInformation; + + void initializeLoadInformation() + { + s_processLoadInformation["ConnectionServer"] = ConfigTaskManager::getLoadConnectionServer(); + s_processLoadInformation["PlanetServer"] = ConfigTaskManager::getLoadPlanetServer(); + s_processLoadInformation["SwgGameServer"] = ConfigTaskManager::getLoadGameServer(); + } + + float getLoadForProcess(const std::string & name) + { + float result = 0.0f; + + for (std::map::const_iterator i = s_processLoadInformation.begin(); i != s_processLoadInformation.end(); ++i) + { + if (name.find(i->first) != std::string::npos) + { + result = i->second; + break; + } + } + + return result; + } + + struct RestartRequest + { + std::string commandLine; + unsigned long timeQueued; + TaskManager::SpawnDelaySeconds spawnDelay; + }; + std::vector s_restartRequests; + + struct QueuedSpawnRequest + { + std::string processName; + std::string options; + std::string nodeLabel; + unsigned long timeQueued; + TaskManager::SpawnDelaySeconds spawnDelay; + }; + + std::vector s_queuedSpawnRequests; + std::vector s_delayedSpawnRequests; + struct OutstandingSpawnRequestAck + { + OutstandingSpawnRequestAck(const std::string n, const Archive::ByteStream & a, int t) : + nodeLabel(n), request(a), transactionId(t) + { + } + std::string nodeLabel; + Archive::ByteStream request; + int transactionId; + }; + + std::vector s_outstandingSpawnRequestAcks; +} + +using namespace TaskManagerNameSpace; +//----------------------------------------------------------------------- + +TaskManager::NodeEntry::NodeEntry(const std::string & addr, const std::string & label, int index) : + m_address(addr), + m_nodeLabel(label), + m_nodeNumber(index) +{ +} + +//----------------------------------------------------------------------- + +bool TaskManager::NodeEntry::operator==(const NodeEntry & rhs) const +{ + return (m_nodeNumber == rhs.m_nodeNumber); +} + +//----------------------------------------------------------------------- + +bool TaskManager::NodeEntry::operator==(const std::string & address) const +{ + return (m_address == address); +} + +//----------------------------------------------------------------------- + +TaskManager::TaskManager() : +m_processEntries(), +m_localServers(), +m_remoteServers(), +m_nodeLabel(), +m_startTime(::time(NULL)), +m_nodeList(), +m_nodeNumber(-1), +m_nodeToConnectToList(), +m_managerService(0), +m_taskService(0), +m_sysInfoSource(new TaskManagerSysInfo), +m_centralConnection(0) +{ + processRcFile(); + processEnvironmentVariables(); + setupNodeList(); +} + +//----------------------------------------------------------------------- + +TaskManager::~TaskManager() +{ + delete m_sysInfoSource; +} + +//----------------------------------------------------------------------- + +void TaskManager::processEnvironmentVariables() +{ + int const numberOfEnvironmentVariables = ConfigTaskManager::getNumberOfEnvironmentVariables(); + + for (int i = 0; i < numberOfEnvironmentVariables; ++i) + { + char const * const p = ConfigTaskManager::getEnvironmentVariable(i); + if(p) + { + const char* plus = strchr(p, '+'); + const char* value = strchr(p, '='); + WARNING_STRICT_FATAL(!value, ("Could not find an equal sign (=) in environment setting %s", p)); + WARNING_STRICT_FATAL(plus && value != plus + 1, ("Mismatched += sign in %s.", p)); +#ifdef _DEBUG + const char* dollar = strchr(p, '$'); + DEBUG_FATAL(dollar, ("We don't support using variables (with $) within environment variables yet %s", p)); +#endif + std::string key(p, (plus ? plus : value) - p); + ++value; + if (plus) + { + if (!EnvironmentVariable::addToEnvironmentVariable(key.c_str(), value)) + { + WARNING(true, ("Failed to add environment variable %s", p)); + } + } + else + { + if (!EnvironmentVariable::setEnvironmentVariable(key.c_str(), value)) + { + WARNING(true, ("Failed to set environment variable %s", p)); + } + } + } + } +} + +//----------------------------------------------------------------------- + +void TaskManager::install() +{ + gs_instance = new TaskManager(); +} + +//----------------------------------------------------------------------- + +void TaskManager::remove() +{ + delete gs_instance; +} + +//----------------------------------------------------------------------- + +void TaskManager::processRcFile() +{ + AbstractFile * file = new StdioFile(ConfigTaskManager::getRcFileName(), "r"); + if(file) + { + if(file->isOpen()) + { + // read spawn directives + int fileLength = file->length(); + if(fileLength > 0) + { + char * buffer = new char[fileLength + 1]; //lint !e737 Loss of sign in promotion from int to unsigned long + IGNORE_RETURN(memset(buffer, 0, fileLength + 1)); //lint !e732 loss of sign in promotion from int to unsigned long + int readResult = file->read(buffer, fileLength); + if(readResult > 0) + { + // parse the file + size_t start = 0; + std::string rcData = buffer; + while(start < rcData.size()) + { + size_t recordEnd = rcData.find_first_of('\n', start); + if(recordEnd < std::string::npos) + { + std::string record = rcData.substr(start, recordEnd - start); + if(record.length() > 0) + { + size_t firstChar = record.find_first_not_of(" \t"); + if(firstChar < std::string::npos) + { + if(record[firstChar] == '#') + { + start = recordEnd + 1; + continue; + } + } + ProcessEntry pe; + + // get server name + size_t serverNameEndPos = record.find_first_of(' ', firstChar); + if(serverNameEndPos < std::string::npos) + { + pe.processName = record.substr(firstChar, serverNameEndPos - firstChar); + + // get target host directive + firstChar = record.find_first_not_of(' ', serverNameEndPos); + if(firstChar < std::string::npos) + { + size_t hostEndPos = record.find_first_of(' ', firstChar); + if(hostEndPos < std::string::npos) + { + pe.targetHost = record.substr(firstChar, hostEndPos - firstChar); + if(pe.targetHost != "any" && pe.targetHost != "local") + { + Address a(pe.targetHost, 0); + pe.targetHost = a.getHostAddress(); + } + + // get executable name + firstChar = record.find_first_not_of(' ', hostEndPos); + if(firstChar < std::string::npos) + { + size_t executableEndPos = record.find_first_of(' ', firstChar); + if(executableEndPos < std::string::npos) + { + pe.executable = record.substr(firstChar, executableEndPos - firstChar); + + // get options + firstChar = record.find_first_not_of(' ', executableEndPos); + if(firstChar < std::string::npos) + { + pe.options = record.substr(firstChar); + + IGNORE_RETURN(m_processEntries.insert(std::make_pair(pe.processName, pe))); + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc entry [%s]\n", record.c_str())); + } + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc entry [%s]\n", record.c_str())); + } + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc entry [%s]\n", record.c_str())); + } + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc entry [%s]\n", record.c_str())); + } + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc entry [%s]\n", record.c_str())); + } + } + else + { + REPORT_LOG(true, ("Could not parse taskmanager.rc ent-ry [%s]\n", record.c_str())); + } +// m_localServers.insert(std::pair(record,0)); +// IGNORE_RETURN(loadOnStart.insert(record)); + } + } + else + { + break; + } + start = recordEnd + 1; + } + } + delete [] buffer; + } + file->close(); + delete file; + } + } + +} + +//----------------------------------------------------------------------- + +void TaskManager::setupNodeList() +{ + char buffer[64]; + const char* result = NULL; + int nodeIndex = 0; + bool found = true; + + const std::string & localAddress = NetworkHandler::getHostName(); + const std::string localName = NetworkHandler::getHumanReadableHostName(); + + m_nodeNumber = -1; + + do + { + found = false; + sprintf(buffer, "node%d", nodeIndex); + result = ConfigFile::getKeyString("TaskManager", buffer, NULL); + if (result) + { + NodeEntry n(result, buffer, nodeIndex); + m_nodeList.push_back(n);; + found = true; + if (result == localAddress || result == localName) + { + m_nodeNumber = nodeIndex; + m_nodeLabel = buffer; + } + ++nodeIndex; + } + + } while(found); + + if (m_nodeList.empty()) + { + m_nodeLabel = "node0"; + m_nodeNumber = 0; + } + + if (m_nodeNumber != -1) + { + DEBUG_REPORT_LOG(true, ("This taskmanager is node %s\n", m_nodeLabel.c_str())); + } + else + { + WARNING(true, ("Could not find node for this host: %s.", localAddress.c_str())); + } + + std::vector::iterator i = m_nodeList.begin(); + for (; i != m_nodeList.end(); ++i) + { + if (m_nodeNumber > i->m_nodeNumber) + { + DEBUG_REPORT_LOG(true, ("Adding node %d to attempt list\n", i->m_nodeNumber)); + m_nodeToConnectToList.push_back(*i); + } + } +} + +//----------------------------------------------------------------------- + +std::string TaskManager::executeCommand(const std::string & command) +{ + std::string result = "unknown command"; + + if(command == "start") + { + startCluster(); + result = "start command issued and handled by the TaskManager"; + } + else if(command == "stop") + { + stopCluster(); + result = "stop command issued and handled by the TaskManager"; + } + else if(command == "public") + { + SetConnectionServerPublic p(true); + sendToCentralServer(p); + result = "public command issued and handled by the TaskManager"; + } + else if(command == "private") + { + SetConnectionServerPublic p(false); + sendToCentralServer(p); + result = "private command issued and handled by the TaskManager"; + } + else if(command == "taskConnectionCount") + { + char countBuf[32]; + IGNORE_RETURN(snprintf(countBuf, sizeof(countBuf)-1, "%d", ManagerConnection::getConnectionCount())); + countBuf[sizeof(countBuf)-1] = '\0'; + result = countBuf; + } + else if(command == "exit") + { + stopCluster(); + ms_done = true; + result = "exiting"; + } + else if(command == "runState") + { + result = "running"; + } + LOG("TaskManager",("Execute command: %s.", result.c_str())); + return result; +} + +//----------------------------------------------------------------------- + +const float TaskManager::getLoadAverage() +{ + return Locator::getMyLoad(); +} + +//----------------------------------------------------------------------- + +TaskManager & TaskManager::instance() +{ + NOT_NULL(gs_instance); + return *gs_instance; +} + +//----------------------------------------------------------------------- + +void TaskManager::killProcess(const TaskKillProcess & killProcessMessage) +{ + if(NetworkHandler::isAddressLocal(killProcessMessage.getHostName()) || killProcessMessage.getHostName() == instance().m_nodeLabel) + { + // local destroy find process by pid + + std::set >::iterator i = instance().m_localServers.begin(); + while (i != instance().m_localServers.end()) + { + if(i->second == killProcessMessage.getPid()) + { + // confirmed kill + if(killProcessMessage.getForceCore()) + ProcessSpawner::forceCore(killProcessMessage.getPid()); + else + ProcessSpawner::kill(killProcessMessage.getPid()); + + // emit kill notification message + static MessageDispatch::Transceiver t; + static ProcessKilled k; + k.commandLine = (*i).first; + k.hostName = killProcessMessage.getHostName(); + t.emitMessage(k); + instance().m_localServers.erase(i++); + Locator::decrementMyLoad(getLoadForProcess(k.commandLine)); + } + else + ++i; + } + } +} + +//----------------------------------------------------------------------- + +void TaskManager::run() +{ + NetworkHandler::install(); + NetworkSetupData setup; + setup.port = ConfigTaskManager::getGameServicePort(); + setup.maxConnections = 100; + setup.bindInterface = ConfigTaskManager::getGameServiceBindInterface(); + instance().m_taskService = new Service(ConnectionAllocator(), setup); + setup.port = ConfigTaskManager::getTaskManagerServicePort(); + setup.bindInterface = ConfigTaskManager::getTaskManagerServiceBindInterface(); + instance().m_managerService = new Service(ConnectionAllocator(), setup); + setup.maxConnections = 32; + setup.port = ConfigTaskManager::getConsoleConnectionPort(); + setup.bindInterface = ConfigTaskManager::getConsoleServiceBindInterface(); + instance().m_consoleService = new Service(ConnectionAllocator(), setup); + + SetupSharedLog::install("TaskManager"); + Locator::install(); + initializeRestartDelayInformation(); + initializeLoadInformation(); + + if(ConfigTaskManager::getAutoStart()) + startCluster(); + + while (!ms_done) + { + TaskManager::update(); + } + + NetworkHandler::update(); + NetworkHandler::dispatch(); + + SetupSharedLog::remove(); + NetworkHandler::remove(); +} + +//----------------------------------------------------------------------- + +unsigned long TaskManager::startServerLocal(const ProcessEntry & pe, const std::string & options) +{ + unsigned long pid = 0; + // build the command + std::string cmd = pe.executable + " " + pe.options + " " + options; + DEBUG_REPORT_LOG(true, ("Now Spawning process: %s\n", cmd.c_str())); + LOG("TaskManager", ("Now spawning process: (%s). I am %s (%s). My Load is %f.", cmd.c_str(), NetworkHandler::getHumanReadableHostName().c_str(), NetworkHandler::getHostName().c_str(), Locator::getMyLoad())); + if( (pid = ProcessSpawner::execute(cmd)) > 0) + { + Locator::incrementMyLoad(getLoadForProcess(pe.processName)); + IGNORE_RETURN(instance().m_localServers.insert(std::make_pair(cmd, pid))); + static MessageDispatch::Transceiver p; + static ProcessStarted s; + s.pid = pid; + s.hostName = NetworkHandler::getHostName(); + s.commandLine = cmd; + p.emitMessage(s); + } + return pid; +} + +//----------------------------------------------------------------------- +/** Start a new process + + Processes are read from the taskmanager.rc file. A remote process + or the local task manager requests a process startup. The process name + must match one in the taskmanager.rc file. The rc contains default + options for the local system. Options passed in the request are + appended to the command line and duplicates will override the + options specified in the rc file. +*/ +unsigned long TaskManager::startServer(const std::string & processName, const std::string & options, const std::string& nodeLabel, const SpawnDelaySeconds spawnDelay) +{ + unsigned long pid = 0; + static const std::string localAddress(NetworkHandler::getHostName()); + + DEBUG_REPORT_LOG(true, ("Now trying to start server %s %s on %s, spawn delay %u\n", processName.c_str(), options.c_str(), nodeLabel.c_str(), spawnDelay)); + DEBUG_REPORT_LOG(true, ("Local address is %s and i am node %s\n", localAddress.c_str(), getNodeLabel().c_str())); + + // get process + std::map::const_iterator f = instance().m_processEntries.find(processName); + if(f != instance().m_processEntries.end()) + { + // if there's a spawn delay, queue the spawn request + if (spawnDelay > 0) + { + QueuedSpawnRequest r; + r.processName = processName; + r.options = options; + r.nodeLabel = nodeLabel; + r.timeQueued = Clock::timeSeconds(); + r.spawnDelay = spawnDelay; + s_delayedSpawnRequests.push_back(r); + + return 0; + } + + const ProcessEntry pe = (*f).second; + + // does the process run on this box? + if(pe.targetHost == "local" || pe.targetHost == getNodeLabel() || nodeLabel == getNodeLabel() || nodeLabel == "local") + { + if(processName == "SwgGameServer" && Locator::getMyLoad() + getLoadForProcess(processName) >= Locator::getMyMaximumLoad() && ManagerConnection::getConnectionCount() > 1) + { + ManagerConnection * conn = Locator::getServer("node0"); + if(conn) + { + WARNING(true, ("Tried to spawn a SwgGameServer on this host, but would exceed spawn limit, sending request back to master node with an update containing my load level")); + TaskSpawnProcess spawn("any", processName, options); + conn->send(spawn); + } + else + { + FATAL(true, ("Tried to exceed load limits spawning a game server and could not find the master node to send a spawn request to!")); + } + } + else + { + pid = startServerLocal(pe, options); + } + } + else if(pe.targetHost == "any") + { + if (nodeLabel == "any") + { + // if this is node0, then we can authoritatively spawn this process + if(getNodeLabel() == "node0") + { + // select a task manager on which to spawn the server + // find the best target + float cost = getLoadForProcess(pe.processName); + ManagerConnection * conn = Locator::getBestServer(pe.processName, options, cost); + if(!conn) + { + + if(ManagerConnection::getConnectionCount() < 1) + pid = startServerLocal(pe, options); + else + { + WARNING(true, ("No hosts are available to spawn a process(%s) costing %f without exceeding the host's load limit", processName.c_str(), cost)); + LOG("TaskManager", ("No hosts are available to spawn a process(%s) costing %f without exceeding the host's load limit. Deferring spawn", processName.c_str(), cost)); + // queue the spawn request for another frame + QueuedSpawnRequest r; + r.processName = processName; + r.options = options; + r.nodeLabel = nodeLabel; + r.timeQueued = Clock::timeSeconds(); + r.spawnDelay = spawnDelay; + s_queuedSpawnRequests.push_back(r); + } + } + else + { + std::string label = "uninitialized label"; + if(conn->getNodeLabel()) + label = *conn->getNodeLabel(); + DEBUG_FATAL(!conn->getNodeLabel(), ("Told to send to an uninitialized label\n")); + TaskSpawnProcess spawn( (conn->getNodeLabel() ? *conn->getNodeLabel() : "local"), pe.processName, options); + conn->send(spawn); + Locator::incrementServerLoad(conn->getNodeLabel() ? *conn->getNodeLabel() : "local", cost); + LOG("TaskManager", ("Now spawning process: Sent spawn request to %s (%s) to spawn (%s %s). I think the load on %s is %f/%f", label.c_str(), conn->getRemoteAddress().c_str(), processName.c_str(), options.c_str(), label.c_str(), Locator::getServerLoad(label), Locator::getServerMaximumLoad(label))); + } + } + else + { + // this is not the master node, prevent race conditions + // if two task managers try to select the same node + // forward request to node0 + ManagerConnection * conn = Locator::getServer("node0"); + if(conn) + { + LOG("TaskManager", ("Forwarding spawn request (%s) to master node. My load is %f", processName.c_str(), Locator::getMyLoad())); + TaskSpawnProcess spawn("any", pe.processName, options); + conn->send(spawn); + } + } + } + else //hostName is specified, either a config file or the master node is requesting the spawn + { + // start on the specified task manager + ManagerConnection * conn = Locator::getServer(nodeLabel); + if (!conn) + { + REPORT_LOG(true, + ("Could not spawn %s on %s because that process is not connected to this task manager! Spawn deferred...\n", + pe.processName.c_str(), nodeLabel.c_str())); + + // ProcessEntry came from the taskmanager.rc file, so + // we need to update it with the correct targetHost + // and options information in order to be able to + // spawn the process when the specified task + // manager/targetHost is up + ProcessEntry peCopy = pe; + + peCopy.targetHost = nodeLabel; + peCopy.options = options; + + ms_deferredSpawns.push_back(peCopy); + } + else + { + TaskSpawnProcess spawn(nodeLabel, pe.processName, options); + conn->send(spawn); + Locator::incrementServerLoad(nodeLabel, getLoadForProcess(pe.processName)); + LOG("TaskManager", ("Now spawning process: Sent spawn request to %s (%s) to spawn (%s %s). I think the load on %s is %f/%f", nodeLabel.c_str(), conn->getRemoteAddress().c_str(), pe.processName.c_str(), options.c_str(), nodeLabel.c_str(), Locator::getServerLoad(nodeLabel), Locator::getServerMaximumLoad(nodeLabel))); + + // put this on a pending queue waiting for an ack + Archive::ByteStream bs; + spawn.pack(bs); + OutstandingSpawnRequestAck ack(nodeLabel, bs, spawn.getTransactionId()); + + s_outstandingSpawnRequestAcks.push_back(ack); + } + } + } + else + { + // start on the specified task manager + ManagerConnection * conn = Locator::getServer(pe.targetHost); + if (!conn) + { + + REPORT_LOG(true, ("Could not spawn %s on %s because %s is not connected to this task manager! Spawn deferred...\n", pe.processName.c_str(), pe.targetHost.c_str(), pe.targetHost.c_str())); + + //defer spawn?? + // ProcessEntry came from the taskmanager.rc file, so + // we need to update it with the correct options + // information in order to be able to spawn the process + // when the specified task manager/targetHost is up + ProcessEntry peCopy = pe; + + peCopy.options = options; + + ms_deferredSpawns.push_back(peCopy); + } + else + { + TaskSpawnProcess spawn(pe.targetHost, pe.processName, options); + conn->send(spawn); + Locator::incrementServerLoad(*conn->getNodeLabel(), getLoadForProcess(pe.processName)); + LOG("TaskManager", ("Now spawning process: Sent spawn request to %s (%s) to spawn (%s %s). I think the load on %s is %f/%f", conn->getNodeLabel()->c_str(), conn->getRemoteAddress().c_str(), pe.processName.c_str(), options.c_str(), conn->getNodeLabel()->c_str(), Locator::getServerLoad(*conn->getNodeLabel()), Locator::getServerMaximumLoad(*conn->getNodeLabel()))); + // put this on a pending queue waiting for an ack + Archive::ByteStream bs; + spawn.pack(bs); + OutstandingSpawnRequestAck ack(nodeLabel, bs, spawn.getTransactionId()); + s_outstandingSpawnRequestAcks.push_back(ack); + } + } + } + + return pid; +} + +//----------------------------------------------------------------------- + +void TaskManager::retryConnection(ManagerConnection const *connection) +{ + std::vector::iterator i = std::find(instance().m_nodeList.begin(), instance().m_nodeList.end(), connection->getRemoteAddress()); + if (i != instance().m_nodeList.end()) + { + instance().m_nodeToConnectToList.push_back(*i); + } + else + { + WARNING(true, ("could not find node for %s after it closed connection", connection->getRemoteAddress().c_str())); + } +} + +//----------------------------------------------------------------------- + +void TaskManager::runSpawnRequestQueue() +{ + if (!s_queuedSpawnRequests.empty()) + { + // create a temporary vector to iterate + std::vector const temp = s_queuedSpawnRequests; + + // clear the request queue vector + // if a process can't spawn, it will be re-added to + // the vector the the next run of the request queue + s_queuedSpawnRequests.clear(); + + for (std::vector::const_iterator i = temp.begin(); i != temp.end(); ++i) + IGNORE_RETURN(startServer(i->processName, i->options, i->nodeLabel, 0)); + } +} + +//----------------------------------------------------------------------- + +void TaskManager::update() +{ + NetworkHandler::update(); + NetworkHandler::dispatch(); + + Console::update(); + + while(Console::hasPendingCommand()) + { + IGNORE_RETURN(executeCommand(Console::getNextCommand())); + } + + Clock::setFrameRateLimit(4.0f); + + static uint32 lastTime = 0; + uint32 currentTime = Clock::timeMs(); + if (!instance().m_nodeToConnectToList.empty() && currentTime > lastTime + 1000) + { + std::vector::iterator i = instance().m_nodeToConnectToList.begin(); + for(; i != instance().m_nodeToConnectToList.end(); ++i) + { + new ManagerConnection(i->m_address, ConfigTaskManager::getTaskManagerServicePort()); + } + instance().m_nodeToConnectToList.clear(); + lastTime = currentTime; + } + +#if 0 + instance().m_sysInfoSource->update(); + if (ms_doUpdate) + { + Locator::updateAllLoads(); + ms_doUpdate = false; + } +#endif//0 + + // get process status + std::set >::iterator i; + for(i = instance().m_localServers.begin(); i != instance().m_localServers.end();) + { + if(! ProcessSpawner::isProcessActive((*i).second)) + { + LOG("TaskProcessDied", ("PROCESS DIED: %s", i->first.c_str())); + // advise the master node that a process has died + TaskProcessDiedMessage died(i->second, i->first); + + // is this the master node? + if(getNodeLabel() == "node0") + { + // tell CentralServer (if it is still around), that the process died + if(instance().m_centralConnection) + { + LOG("TaskProcessDied", ("advising central that the process is dead")); + instance().m_centralConnection->send(died); + } + } + else + { + ManagerConnection * master = Locator::getServer("node0"); + if(master) + { + LOG("TaskProcessDied", ("advising master node that the process is dead")); + master->send(died); + } + } + // destroy process + Locator::decrementMyLoad(getLoadForProcess(i->first)); + ProcessAborted a; + a.commandLine = (*i).first; + a.hostName = NetworkHandler::getHostName(); + MessageDispatch::emitMessage(a); + + if (!fopen(".norestart","r")) + { + // respawn CentralServer or LogServer + if ( (a.commandLine.find("CentralServer") != std::string::npos && ConfigTaskManager::getRestartCentral()) + || a.commandLine.find("LogServer") != std::string::npos + || a.commandLine.find("MetricsServer") != std::string::npos + || a.commandLine.find("CommoditiesServer") != std::string::npos + || a.commandLine.find("CommodityServer") != std::string::npos + || a.commandLine.find("TransferServer") != std::string::npos) + { + RestartRequest r; + r.commandLine = (*i).first; + r.timeQueued = Clock::timeSeconds(); + r.spawnDelay = getRestartDelayInformation((*i).first); + + s_restartRequests.push_back(r); + } + instance().m_localServers.erase(i++); + if(i == instance().m_localServers.end()) + break; + } + } + else + ++i; + } + + if (!s_restartRequests.empty()) + { + for (std::vector::iterator i = s_restartRequests.begin(); i != s_restartRequests.end(); ++i) + { + if ((i->spawnDelay == 0) || ((i->timeQueued + i->spawnDelay) < Clock::timeSeconds())) + { + unsigned long pid = ProcessSpawner::execute((i->commandLine)); + Locator::incrementMyLoad(getLoadForProcess(i->commandLine)); + IGNORE_RETURN(instance().m_localServers.insert(std::make_pair((i->commandLine), pid))); + + IGNORE_RETURN(s_restartRequests.erase(i)); + + // just do 1 per frame to spread out the load + break; + } + } + } + + if (!ms_deferredSpawns.empty()) + { + // flush deferred spawns + std::vector::const_iterator procIter; + std::vector failures; + const std::vector & def = ms_deferredSpawns; + + for(procIter = def.begin(); procIter != def.end(); ++procIter) + { + ManagerConnection* conn = Locator::getServer(procIter->targetHost); + if (conn) + { + TaskSpawnProcess spawn((*procIter).targetHost, (*procIter).processName, (*procIter).options); + conn->send(spawn); + REPORT_LOG(true, ("Sent deferred spawn request for %s to %s\n", (*procIter).processName.c_str(), (*procIter).targetHost.c_str())); + } + else + { + failures.push_back((*procIter)); + } + } + + ms_deferredSpawns = failures; + } + + if (!s_delayedSpawnRequests.empty()) + { + for (std::vector::iterator i = s_delayedSpawnRequests.begin(); i != s_delayedSpawnRequests.end(); ++i) + { + if ((i->timeQueued + i->spawnDelay) < Clock::timeSeconds()) + { + IGNORE_RETURN(startServer(i->processName, i->options, i->nodeLabel, 0)); + IGNORE_RETURN(s_delayedSpawnRequests.erase(i)); + + // just do 1 per frame to spread out the load + break; + } + } + } + + // slave TaskManager will periodically send the system time to the + // the TaskManager to detect when/if system time gets out of sync + + // master TaskManager will periodically send to CentralServer the list + // of slave TaskManager that has disconnected but has not reconnected, + // so that an alert can be made in SOEMon so ops can see it and restart + // the disconnected TaskManager + static time_t timeSystemTimeCheck = ::time(NULL) + ConfigTaskManager::getSystemTimeCheckIntervalSeconds(); + time_t const timeNow = ::time(NULL); + if (timeSystemTimeCheck <= timeNow) + { + if (getNodeLabel() != "node0") + { + ManagerConnection * master = Locator::getServer("node0"); + if (master) + { + GenericValueTypeMessage > msg("SystemTimeCheck", std::make_pair(getNodeLabel(), static_cast(timeNow))); + master->send(msg); + } + } + else + { + std::string disconnectedTaskManagerList; + std::map const & disconnectedTaskManager = Locator::getClosedConnections(); + if (!disconnectedTaskManager.empty()) + { + char buffer[128]; + for (std::map::const_iterator iter = disconnectedTaskManager.begin(); iter != disconnectedTaskManager.end(); ++iter) + { + snprintf(buffer, sizeof(buffer)-1, "%s (%s)", iter->first.c_str(), iter->second.c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + if (!disconnectedTaskManagerList.empty()) + disconnectedTaskManagerList += ", "; + + disconnectedTaskManagerList += buffer; + } + } + + GenericValueTypeMessage disconnectedTaskManagerMessage("DisconnectedTaskManagerMessage", disconnectedTaskManagerList); + TaskManager::sendToCentralServer(disconnectedTaskManagerMessage); + } + + timeSystemTimeCheck = timeNow + ConfigTaskManager::getSystemTimeCheckIntervalSeconds(); + } + + GameConnection::update(); + Clock::update(); + Clock::limitFrameRate(); +} + +//----------------------------------------------------------------------- + +void TaskManager::sendToCentralServer(const GameNetworkMessage & message) +{ + if(instance().m_centralConnection) + { + instance().m_centralConnection->send(message); + } +} + +//----------------------------------------------------------------------- + +void TaskManager::setCentralConnection(TaskConnection * newConnection) +{ + instance().m_centralConnection = newConnection; +} + +//----------------------------------------------------------------------- + +void TaskManager::addToGameConnections(int x) +{ + ms_numGameConnections += x; + ms_doUpdate = true; +} + +//----------------------------------------------------------------------- +int TaskManager::getNumGameConnections() +{ + return ms_numGameConnections; +} + +//----------------------------------------------------------------------- + +void TaskManager::onDatabaseIdle(bool isIdle) +{ + if (!ms_preloadFinished) + return; + + if (isIdle) + { + ++ms_idleFrames; + if (ConfigTaskManager::getPublishMode() && ms_idleFrames>5) // wait for a few idle frames in a row, just to be safe + { + DEBUG_REPORT_LOG(true,("Preloading is done and database is idle. Shutting down cluster\n")); + stopCluster(); + ms_done = true; + } + } + else + { + ms_idleFrames=0; + } +} + +// ---------------------------------------------------------------------- + +void TaskManager::startCluster() +{ + IGNORE_RETURN(TaskManager::startServer("TransferServer", "", "local", 0)); + IGNORE_RETURN(TaskManager::startServer("MetricsServer", "", "local", 0)); + IGNORE_RETURN(TaskManager::startServer("LogServer", "", "local", 0)); + std::string options = "-s CentralServer loginServerAddress="; + options += ConfigTaskManager::getLoginServerAddress(); + options += " clusterName=" + std::string(ConfigTaskManager::getClusterName()); + IGNORE_RETURN(TaskManager::startServer("CentralServer", options, "local", 0)); +} + +// ---------------------------------------------------------------------- + +void TaskManager::stopCluster() +{ + std::set >::iterator i; + for(i = instance().m_localServers.begin(); i != instance().m_localServers.end(); ++i) + { + ProcessSpawner::kill((*i).second); + } + instance().m_localServers.clear(); +} + +// ---------------------------------------------------------------------- + +void TaskManager::onPreloadFinished() +{ + ms_preloadFinished = true; +} + +// ---------------------------------------------------------------------- + +void TaskManager::resendUnacknowledgedSpawnRequests(Connection * connection, const std::string & nodeLabel) +{ + std::vector::iterator i; + for(i = s_outstandingSpawnRequestAcks.begin(); i != s_outstandingSpawnRequestAcks.end(); ++i) + { + if(i->nodeLabel == nodeLabel) + { + connection->send(i->request, true); + } + } +} + +// ---------------------------------------------------------------------- + +void TaskManager::removePendingSpawnProcessAck(int transactionId) +{ + std::vector::iterator i; + for(i = s_outstandingSpawnRequestAcks.begin(); i != s_outstandingSpawnRequestAcks.end();) + { + if(i->transactionId == transactionId) + { + i = s_outstandingSpawnRequestAcks.erase(i); + } + else + { + ++i; + } + } +} +// ====================================================================== diff --git a/engine/server/application/TaskManager/src/shared/TaskManager.h b/engine/server/application/TaskManager/src/shared/TaskManager.h new file mode 100644 index 00000000..cb5c5a64 --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskManager.h @@ -0,0 +1,179 @@ +// TaskManager.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_TaskManager_H +#define _INCLUDED_TaskManager_H + +#include +#include +#include +#include + +//----------------------------------------------------------------------- + +class Connection; +class ConsoleConnection; +class GameNetworkMessage; +class LoginConnection; +class Service; +class ManagerConnection; +class TaskConnection; +class TaskKillProcess; +class TaskManagerSysInfo; + +//----------------------------------------------------------------------- + +struct ProcessKilled +{ + std::string commandLine; + std::string hostName; +}; + +//----------------------------------------------------------------------- + +struct ProcessAborted +{ + std::string commandLine; + std::string hostName; +}; + +//----------------------------------------------------------------------- + +struct ProcessStarted +{ + unsigned long pid; + std::string commandLine; + std::string hostName; +}; + +//----------------------------------------------------------------------- + +struct RequestProcessKill +{ + std::string commandLine; + std::string hostName; + unsigned long pid; +}; + +//----------------------------------------------------------------------- + +struct RequestProcessStart +{ + std::string commandLine; + std::string hostName; +}; + +//----------------------------------------------------------------------- + +struct ProcessEntry +{ + std::string processName; + std::string targetHost; + std::string executable; + std::string options; +}; + +//----------------------------------------------------------------------- + +class TaskManager +{ +public: + typedef unsigned int SpawnDelaySeconds; + + TaskManager(); + ~TaskManager(); + static std::string executeCommand (const std::string & command); + static const float getLoadAverage (); + static const std::string & getNodeLabel(); + static time_t getStartTime(); + static void killProcess (const TaskKillProcess &); + static void retryConnection (ManagerConnection const *connection); + static void sendToCentralServer (const GameNetworkMessage & msg); + static void setCentralConnection (TaskConnection * connection); + static void onDatabaseIdle (bool isIdle); + static void onPreloadFinished (); + static void runSpawnRequestQueue (); + static unsigned long startServer (const std::string & processName, const std::string & options, const std::string& hostName, SpawnDelaySeconds spawnDelay); + static void stopCluster (); + static void resendUnacknowledgedSpawnRequests (Connection * connection, const std::string & nodeLabel); + static void removePendingSpawnProcessAck (int transactionId); + + static void install (); + static void remove (); + static void run (); + static void update (); + + static const std::set > & getLocalServers(); + static const std::map > & getRemoteServers(); + + static void addToGameConnections(int x); + static int getNumGameConnections(); + +private: + TaskManager & operator = (const TaskManager & rhs); + TaskManager(const TaskManager & source); + static TaskManager & instance(); + + void processRcFile(); + void processEnvironmentVariables(); + void setupNodeList(); + static unsigned long startServerLocal(const ProcessEntry & processEntry, const std::string & options); + static void startCluster(); + +private: + + struct NodeEntry + { + + NodeEntry(const std::string &, const std::string & , int); + bool operator==(const NodeEntry &) const; + bool operator==(const std::string & address) const; + + std::string m_address; + std::string m_nodeLabel; + int m_nodeNumber; + + }; + + std::map m_processEntries; + std::set > m_localServers; + std::map > m_remoteServers; + std::string m_nodeLabel; + time_t const m_startTime; + std::vector m_nodeList; + int m_nodeNumber; + std::vector m_nodeToConnectToList; + + Service * m_managerService; + Service * m_taskService; + Service * m_consoleService; + TaskManagerSysInfo * m_sysInfoSource; + TaskConnection * m_centralConnection; + +}; + +//----------------------------------------------------------------------- + +inline const std::set > & TaskManager::getLocalServers() +{ + return instance().m_localServers; +} + +//----------------------------------------------------------------------- + +inline const std::string& TaskManager::getNodeLabel() +{ + return instance().m_nodeLabel; +} + +//----------------------------------------------------------------------- + +inline time_t TaskManager::getStartTime() +{ + return instance().m_startTime; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_TaskManager_H diff --git a/engine/server/application/TaskManager/src/shared/TaskManagerSysInfo.h b/engine/server/application/TaskManager/src/shared/TaskManagerSysInfo.h new file mode 100644 index 00000000..217d8c5f --- /dev/null +++ b/engine/server/application/TaskManager/src/shared/TaskManagerSysInfo.h @@ -0,0 +1,28 @@ +// TaskManagerSysInfo.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_TaskManagerSysInfo_H +#define _INCLUDED_TaskManagerSysInfo_H + +#include +//----------------------------------------------------------------------- + +class TaskManagerSysInfo +{ +public: + TaskManagerSysInfo(); + ~TaskManagerSysInfo(); + + void update(); + const float getScore () const; + +private: + TaskManagerSysInfo & operator = (const TaskManagerSysInfo & rhs); + TaskManagerSysInfo(const TaskManagerSysInfo & source); + std::list averageScore; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_TaskManagerSysInfo_H diff --git a/engine/server/application/TaskManager/src/win32/ConsoleInput.cpp b/engine/server/application/TaskManager/src/win32/ConsoleInput.cpp new file mode 100644 index 00000000..dfd6c431 --- /dev/null +++ b/engine/server/application/TaskManager/src/win32/ConsoleInput.cpp @@ -0,0 +1,22 @@ +// ConsoleInput.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "Console.h" +#include + +//----------------------------------------------------------------------- + +const char Console::getNextChar() +{ + char result = 0; + if(_kbhit()) + result = static_cast(_getche()); + return result; +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/win32/EnvironmentVariable.cpp b/engine/server/application/TaskManager/src/win32/EnvironmentVariable.cpp new file mode 100644 index 00000000..017b221e --- /dev/null +++ b/engine/server/application/TaskManager/src/win32/EnvironmentVariable.cpp @@ -0,0 +1,33 @@ +#include "FirstTaskManager.h" + +namespace EnvironmentVariable +{ + bool addToEnvironmentVariable(const char* key, const char* value) + { + bool retval = false; + char oldValue[256]; + DWORD tmp = GetEnvironmentVariable(key, oldValue, sizeof(oldValue)); + if (tmp != 0) + { + std::string s(oldValue); + s += ";"; + s += value; + + //Bad things happen if the first character happens to be ; (ie from an empty environment string) + const char* newValue = s.c_str(); + if (newValue[0] == ';') + ++newValue; + + retval = (SetEnvironmentVariable(key, newValue) != 0); + } + else + { + retval = (SetEnvironmentVariable(key, value) != 0); + } + return retval; + } + bool setEnvironmentVariable(const char* key, const char* value) + { + return (SetEnvironmentVariable(key, value) != 0); + } +}; diff --git a/engine/server/application/TaskManager/src/win32/ProcessSpawner.cpp b/engine/server/application/TaskManager/src/win32/ProcessSpawner.cpp new file mode 100644 index 00000000..b544a301 --- /dev/null +++ b/engine/server/application/TaskManager/src/win32/ProcessSpawner.cpp @@ -0,0 +1,153 @@ +#include "FirstTaskManager.h" +#include "sharedFoundation/FirstSharedFoundation.h" +#include "ProcessSpawner.h" +#include +#include +#include "TaskManager.h" + +#include + +uint32 ProcessSpawner::prefix; +std::map procById; + +//----------------------------------------------------------------------- + +bool tokenize (const std::string & str, std::vector & result) +{ + size_t end_pos = 0; + size_t start_pos = 0; + + result.clear (); + + for (;;) + { + if (end_pos >= str.size ()) + break; + + start_pos = str.find_first_not_of (' ', end_pos); + + if (start_pos == str.npos) + break; + + //---------------------------------------------------------------------- + + if (str [start_pos] == '\"') + { + if (++start_pos >= str.size ()) + break; + end_pos = str.find_first_of ('\"', start_pos); + } + else + end_pos = str.find_first_of (' ', start_pos); + + //---------------------------------------------------------------------- + + if (start_pos == end_pos) + break; + + if (end_pos == str.npos) + { + result.push_back (str.substr (start_pos)); + break; + } + else + result.push_back (str.substr (start_pos, end_pos - start_pos)); + + ++start_pos; + } + + return true; +} + +uint32 ProcessSpawner::execute(const std::string & processName, const std::vector & parameters) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + char cmd[1024] = {"\0"}; + std::string cmdLine; + + cmdLine = processName.c_str(); + cmdLine += " "; + std::vector::const_iterator i; + for(i = parameters.begin(); i != parameters.end(); ++i) + { + cmdLine += (*i).c_str(); + cmdLine += " "; + } + + _snprintf(cmd, 1024, "%s.exe", processName.c_str()); +// _snprintf(cmd, 1024, "%s", processName.c_str()); + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + + si.cb = sizeof(si); + + const int result = CreateProcess(cmd, const_cast(cmdLine.c_str()), NULL, NULL, false, 0, 0, 0, &si, &pi); + UNREF (result); + +#ifdef _DEBUG + if (!result) + { + DWORD iErr = GetLastError(); + char * errStr = strerror(iErr); + DEBUG_REPORT_LOG(true, ("ProcessSpawner: %s - %s\n", cmd, errStr)); + } +#endif + + procById.insert(std::pair(pi.dwProcessId, pi.hProcess)); + return pi.dwProcessId; +} + +//----------------------------------------------------------------------- + +uint32 ProcessSpawner::execute(const std::string & cmd) +{ + std::vector args; + size_t firstArg = cmd.find_first_of(" "); + std::string processName; + if(firstArg < cmd.size()) + { + std::string a = cmd.substr(firstArg + 1); + tokenize(a, args); + processName = cmd.substr(0, firstArg); + } + else + { + processName = cmd; + } + return execute(processName, args); +} + +//----------------------------------------------------------------------- + +bool ProcessSpawner::isProcessActive(uint32 pid) +{ + bool result = false; + std::map::const_iterator f = procById.find(pid); + if(f != procById.end()) + { + DWORD exitCode; + GetExitCodeProcess((*f).second, &exitCode); + result = (exitCode == STILL_ACTIVE); + } + return result; +} + +//----------------------------------------------------------------------- + +void ProcessSpawner::kill(uint32 pid) +{ + HANDLE p = OpenProcess(PROCESS_TERMINATE, false, (DWORD)pid); + if(p) + TerminateProcess(p, 0); +} + +//----------------------------------------------------------------------- + +void ProcessSpawner::forceCore(const unsigned long pid) +{ + ProcessSpawner::kill(pid); +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/win32/TaskManagerSysInfo.cpp b/engine/server/application/TaskManager/src/win32/TaskManagerSysInfo.cpp new file mode 100644 index 00000000..feadf4f6 --- /dev/null +++ b/engine/server/application/TaskManager/src/win32/TaskManagerSysInfo.cpp @@ -0,0 +1,147 @@ +// TaskManagerSysInfo.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "TaskManagerSysInfo.h" +#pragma warning ( disable : 4201) +#include +#include +//----------------------------------------------------------------------- + +TaskManagerSysInfo::TaskManagerSysInfo() : +averageScore() +{ + update(); +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo::TaskManagerSysInfo(const TaskManagerSysInfo &) +{ + +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo::~TaskManagerSysInfo() +{ +} + +//----------------------------------------------------------------------- + +TaskManagerSysInfo & TaskManagerSysInfo::operator = (const TaskManagerSysInfo & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + } + return *this; +} + +//----------------------------------------------------------------------- + +const float TaskManagerSysInfo::getScore() const +{ + std::list::const_iterator i; + float avg = 0.0f; + for(i = averageScore.begin(); i != averageScore.end(); ++i) + { + avg += (*i); + } + avg = avg / averageScore.size(); + return avg; +} + +//----------------------------------------------------------------------- + +void TaskManagerSysInfo::update() +{ + static int64 activeTime[2] = {0}; + static int64 currentTime[2] = {0}; + + float currentScore = 0.0f; + activeTime[0] = activeTime[1]; + currentTime[0] = currentTime[1]; + activeTime[1] = 0; + + HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + double procAvg = 0.0f; + + MEMORYSTATUS memStat; + GlobalMemoryStatus(&memStat); + + currentScore = static_cast(static_cast(memStat.dwMemoryLoad) * 0.005f); + if(hProcessSnap != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32 pe32 = {0}; + pe32.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(hProcessSnap, &pe32)) + { + do + { + HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION, false, pe32.th32ProcessID); + // some stuf with the enumerated processes + FILETIME createTime = {0}; + FILETIME exitTime = {0}; + FILETIME kernelTime = {0}; + FILETIME userTime = {0}; + GetProcessTimes(proc, &createTime, &exitTime, &kernelTime, &userTime); + int64 totals; + + // SDK docs say: + // It is not recommended that you add and subtract values + // from the FILETIME structure to obtain relative times. Instead, you should + // Copy the resulting FILETIME structure to a ULARGE_INTEGER structure. + // Use normal 64-bit arithmetic on the ULARGE_INTEGER value. + int64 c; + int64 e; + int64 k; + int64 u; + memcpy(&c, &createTime, sizeof(int64)); + memcpy(&e, &exitTime, sizeof(int64)); + memcpy(&k, &kernelTime, sizeof(int64)); + memcpy(&u, &userTime, sizeof(int64)); + + totals = k + u; + + FILETIME fst; + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &fst); + + int64 runTime; + memcpy(&runTime, &fst, sizeof(int64)); + runTime = runTime - c; + + if(c || e || k || u) + { + activeTime[1] += k + e; + } + + } + while (Process32Next(hProcessSnap, &pe32)); + } + } + + FILETIME fst; + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &fst); + memcpy(¤tTime[1], &fst, sizeof(int64)); + int64 timeSlice = currentTime[1] - currentTime[0]; + int64 activeSlice = activeTime[1] - activeTime[0]; + procAvg = static_cast(static_cast(activeSlice) / timeSlice); + //REPORT_LOG(true, ("%f\n", procAvg)); + currentScore = currentScore + static_cast(procAvg * 0.5); + + averageScore.insert(averageScore.end(), currentScore); + + if(averageScore.size() > 100) + averageScore.erase(averageScore.begin()); +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/TaskManager/src/win32/WinMain.cpp b/engine/server/application/TaskManager/src/win32/WinMain.cpp new file mode 100644 index 00000000..9fef3c69 --- /dev/null +++ b/engine/server/application/TaskManager/src/win32/WinMain.cpp @@ -0,0 +1,43 @@ +#include "FirstTaskManager.h" + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedCompression/SetupSharedCompression.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFile/SetupSharedFile.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "sharedThread/SetupSharedThread.h" +#include "TaskManager.h" +#include "ConfigTaskManager.h" + +//===================================================================== + +int main(int argc, char **argv) +{ + SetupSharedThread::install(); + SetupSharedDebug::install(1024); + + //-- setup foundation + SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); + + setupFoundationData.argc = argc; + setupFoundationData.argv = argv; + setupFoundationData.createWindow = false; + setupFoundationData.clockUsesSleep = true; + SetupSharedFoundation::install (setupFoundationData); + + SetupSharedCompression::install(); + SetupSharedNetworkMessages::install(); + ConfigTaskManager::install(); + + //-- run server + SetupSharedFoundation::callbackWithExceptionHandling(TaskManager::run); + + SetupSharedFoundation::remove(); + SetupSharedThread::remove(); + + return 0; +} + +//=====================================================================