First Commit

For Azeroth!
This commit is contained in:
Yehonal
2016-06-26 10:39:44 +02:00
commit e8e94a0a66
3777 changed files with 1419268 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
# Copyright (C)
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE sources_CommandLine CommandLine/*.cpp CommandLine/*.h)
file(GLOB_RECURSE sources_RemoteAccess RemoteAccess/*.cpp RemoteAccess/*.h)
file(GLOB_RECURSE sources_TCSoap TCSoap/*.cpp TCSoap/*.h)
file(GLOB_RECURSE sources_WorldThread WorldThread/*.cpp WorldThread/*.h)
file(GLOB sources_localdir *.cpp *.h)
if (USE_COREPCH)
set(worldserver_PCH_HDR PrecompiledHeaders/worldPCH.h)
set(worldserver_PCH_SRC PrecompiledHeaders/worldPCH.cpp)
endif()
set(worldserver_SRCS
${worldserver_SRCS}
${sources_CommandLine}
${sources_RemoteAccess}
${sources_TCSoap}
${sources_WorldThread}
${sources_localdir}
)
if( WIN32 )
set(worldserver_SRCS
${worldserver_SRCS}
${sources_windows_Debugging}
)
if ( MSVC )
set(worldserver_SRCS
${worldserver_SRCS}
worldserver.rc
)
endif()
endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
${CMAKE_SOURCE_DIR}/src/server/collision/Models
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_SOURCE_DIR}/src/server/game
${CMAKE_SOURCE_DIR}/src/server/game/Accounts
${CMAKE_SOURCE_DIR}/src/server/game/Achievements
${CMAKE_SOURCE_DIR}/src/server/game/Addons
${CMAKE_SOURCE_DIR}/src/server/game/AI
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse/AuctionHouseBot
${CMAKE_SOURCE_DIR}/src/server/game/Battlefield
${CMAKE_SOURCE_DIR}/src/server/game/Battlefield/Zones
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds/Zones
${CMAKE_SOURCE_DIR}/src/server/game/Calendar
${CMAKE_SOURCE_DIR}/src/server/game/Chat
${CMAKE_SOURCE_DIR}/src/server/game/Chat/Channels
${CMAKE_SOURCE_DIR}/src/server/game/Combat
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
${CMAKE_SOURCE_DIR}/src/server/game/DataStores
${CMAKE_SOURCE_DIR}/src/server/game/DungeonFinding
${CMAKE_SOURCE_DIR}/src/server/game/Entities
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Corpse
${CMAKE_SOURCE_DIR}/src/server/game/Entities/DynamicObject
${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item/Container
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Pet
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Player
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Totem
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Transport
${CMAKE_SOURCE_DIR}/src/server/game/Events
${CMAKE_SOURCE_DIR}/src/server/game/Globals
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers
${CMAKE_SOURCE_DIR}/src/server/game/Grids
${CMAKE_SOURCE_DIR}/src/server/game/Groups
${CMAKE_SOURCE_DIR}/src/server/game/Guilds
${CMAKE_SOURCE_DIR}/src/server/game/Handlers
${CMAKE_SOURCE_DIR}/src/server/game/Instances
${CMAKE_SOURCE_DIR}/src/server/game/Loot
${CMAKE_SOURCE_DIR}/src/server/game/Mails
${CMAKE_SOURCE_DIR}/src/server/game/Maps
${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous
${CMAKE_SOURCE_DIR}/src/server/game/Movement
${CMAKE_SOURCE_DIR}/src/server/game/Movement/MovementGenerators
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints
${CMAKE_SOURCE_DIR}/src/server/game/OutdoorPvP
${CMAKE_SOURCE_DIR}/src/server/game/Pools
${CMAKE_SOURCE_DIR}/src/server/game/PrecompiledHeaders
${CMAKE_SOURCE_DIR}/src/server/game/Quests
${CMAKE_SOURCE_DIR}/src/server/game/Reputation
${CMAKE_SOURCE_DIR}/src/server/game/Scripting
${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol
${CMAKE_SOURCE_DIR}/src/server/game/Server
${CMAKE_SOURCE_DIR}/src/server/game/Skills
${CMAKE_SOURCE_DIR}/src/server/game/Spells
${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras
${CMAKE_SOURCE_DIR}/src/server/game/Tools
${CMAKE_SOURCE_DIR}/src/server/game/Warden
${CMAKE_SOURCE_DIR}/src/server/game/Warden/Modules
${CMAKE_SOURCE_DIR}/src/server/game/Weather
${CMAKE_SOURCE_DIR}/src/server/game/World
${CMAKE_SOURCE_DIR}/src/server/game/Misc
${CMAKE_SOURCE_DIR}/src/server/authserver/Server
${CMAKE_SOURCE_DIR}/src/server/authserver/Realms
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/CommandLine
${CMAKE_CURRENT_SOURCE_DIR}/RemoteAccess
${CMAKE_CURRENT_SOURCE_DIR}/TCSoap
${CMAKE_CURRENT_SOURCE_DIR}/WorldThread
${ACE_INCLUDE_DIR}
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
)
add_executable(worldserver
${worldserver_SRCS}
${worldserver_PCH_SRC}
)
if( NOT WIN32 )
set_target_properties(worldserver PROPERTIES
COMPILE_DEFINITIONS _TRINITY_CORE_CONFIG="${CONF_DIR}/worldserver.conf"
)
endif()
add_dependencies(worldserver revision.h)
if( UNIX AND NOT NOJEM )
set(worldserver_LINK_FLAGS "-pthread -lncurses ${worldserver_LINK_FLAGS}")
endif()
set_target_properties(worldserver PROPERTIES LINK_FLAGS "${worldserver_LINK_FLAGS}")
target_link_libraries(worldserver
game
shared
scripts
collision
g3dlib
gsoap
Detour
${JEMALLOC_LIBRARY}
${READLINE_LIBRARY}
${TERMCAP_LIBRARY}
${ACE_LIBRARY}
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${ZLIB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
if( WIN32 )
if ( MSVC )
add_custom_command(TARGET worldserver
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
elseif ( MINGW )
add_custom_command(TARGET worldserver
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/
)
endif()
endif()
if( UNIX )
install(TARGETS worldserver DESTINATION bin)
install(FILES worldserver.conf.dist DESTINATION ${CONF_DIR})
elseif( WIN32 )
install(TARGETS worldserver DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES worldserver.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()
# Generate precompiled header
if( USE_COREPCH )
add_cxx_pch(worldserver ${worldserver_PCH_HDR} ${worldserver_PCH_SRC})
endif()

View File

@@ -0,0 +1,207 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#include "Common.h"
#include "ObjectMgr.h"
#include "World.h"
#include "WorldSession.h"
#include "Configuration/Config.h"
#include "AccountMgr.h"
#include "Chat.h"
#include "CliRunnable.h"
#include "Language.h"
#include "Log.h"
#include "MapManager.h"
#include "Player.h"
#include "Util.h"
#if PLATFORM != PLATFORM_WINDOWS
#include <readline/readline.h>
#include <readline/history.h>
char* command_finder(const char* text, int state)
{
static int idx, len;
const char* ret;
ChatCommand* cmd = ChatHandler::getCommandTable();
if (!state)
{
idx = 0;
len = strlen(text);
}
while ((ret = cmd[idx].Name))
{
if (!cmd[idx].AllowConsole)
{
idx++;
continue;
}
idx++;
//printf("Checking %s \n", cmd[idx].Name);
if (strncmp(ret, text, len) == 0)
return strdup(ret);
if (cmd[idx].Name == NULL)
break;
}
return ((char*)NULL);
}
char** cli_completion(const char* text, int start, int /*end*/)
{
char** matches = NULL;
if (start)
rl_bind_key('\t', rl_abort);
else
matches = rl_completion_matches((char*)text, &command_finder);
return matches;
}
int cli_hook_func()
{
if (World::IsStopped())
rl_done = 1;
return 0;
}
#endif
void utf8print(void* /*arg*/, const char* str)
{
#if PLATFORM == PLATFORM_WINDOWS
wchar_t wtemp_buf[6000];
size_t wtemp_len = 6000-1;
if (!Utf8toWStr(str, strlen(str), wtemp_buf, wtemp_len))
return;
char temp_buf[6000];
CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1);
printf(temp_buf);
#else
{
printf("%s", str);
fflush(stdout);
}
#endif
}
void commandFinished(void*, bool /*success*/)
{
printf("TC> ");
fflush(stdout);
}
#ifdef linux
// Non-blocking keypress detector, when return pressed, return 1, else always return 0
int kb_hit_return()
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
#endif
/// %Thread start
void CliRunnable::run()
{
///- Display the list of available CLI functions then beep
//TC_LOG_INFO("server.worldserver", "");
#if PLATFORM != PLATFORM_WINDOWS
rl_attempted_completion_function = cli_completion;
rl_event_hook = cli_hook_func;
#endif
if (sConfigMgr->GetBoolDefault("BeepAtStart", true))
printf("\a"); // \a = Alert
// print this here the first time
// later it will be printed after command queue updates
printf("TC>");
///- As long as the World is running (no World::m_stopEvent), get the command line and handle it
while (!World::IsStopped())
{
fflush(stdout);
char *command_str ; // = fgets(commandbuf, sizeof(commandbuf), stdin);
#if PLATFORM == PLATFORM_WINDOWS
char commandbuf[256];
command_str = fgets(commandbuf, sizeof(commandbuf), stdin);
#else
command_str = readline("TC>");
rl_bind_key('\t', rl_complete);
#endif
if (command_str != NULL)
{
for (int x=0; command_str[x]; ++x)
if (command_str[x] == '\r' || command_str[x] == '\n')
{
command_str[x] = 0;
break;
}
if (!*command_str)
{
#if PLATFORM == PLATFORM_WINDOWS
printf("TC>");
#else
free(command_str);
#endif
continue;
}
std::string command;
if (!consoleToUtf8(command_str, command)) // convert from console encoding to utf8
{
#if PLATFORM == PLATFORM_WINDOWS
printf("TC>");
#else
free(command_str);
#endif
continue;
}
fflush(stdout);
sWorld->QueueCliCommand(new CliCommandHolder(NULL, command.c_str(), &utf8print, &commandFinished));
#if PLATFORM != PLATFORM_WINDOWS
add_history(command.c_str());
free(command_str);
#endif
}
else if (feof(stdin))
{
World::StopNow(SHUTDOWN_EXIT_CODE);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef __CLIRUNNABLE_H
#define __CLIRUNNABLE_H
/// Command Line Interface handling thread
class CliRunnable : public ACE_Based::Runnable
{
public:
void run();
};
#endif
/// @}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd Trinity Daemon
/// @{
/// \file
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <ace/Version.h>
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Configuration/Config.h"
#include "Log.h"
#include "Master.h"
#ifndef _TRINITY_CORE_CONFIG
# define _TRINITY_CORE_CONFIG "worldserver.conf"
#endif
#ifdef _WIN32
#include "ServiceWin32.h"
char serviceName[] = "worldserver";
char serviceLongName[] = "SunwellCore world service";
char serviceDescription[] = "SunwellCore World of Warcraft emulator world service";
/*
* -1 - not in service mode
* 0 - stopped
* 1 - running
* 2 - paused
*/
int m_ServiceStatus = -1;
#endif
WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database
CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database
LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database
uint32 realmID; ///< Id of the realm
/// Print out the usage string for this program on the console.
void usage(const char* prog)
{
printf("Usage:\n");
printf(" %s [<options>]\n", prog);
printf(" -c config_file use config_file as configuration file\n");
#ifdef _WIN32
printf(" Running as service functions:\n");
printf(" --service run as service\n");
printf(" -s install install service\n");
printf(" -s uninstall uninstall service\n");
#endif
}
/// Launch the Trinity server
extern int main(int argc, char** argv)
{
///- Command line parsing to get the configuration file name
char const* cfg_file = _TRINITY_CORE_CONFIG;
int c = 1;
while (c < argc)
{
if (!strcmp(argv[c], "-c"))
{
if (++c >= argc)
{
printf("Runtime-Error: -c option requires an input argument");
usage(argv[0]);
return 1;
}
else
cfg_file = argv[c];
}
#ifdef _WIN32
if (strcmp(argv[c], "-s") == 0) // Services
{
if (++c >= argc)
{
printf("Runtime-Error: -s option requires an input argument");
usage(argv[0]);
return 1;
}
if (strcmp(argv[c], "install") == 0)
{
if (WinServiceInstall())
printf("Installing service\n");
return 1;
}
else if (strcmp(argv[c], "uninstall") == 0)
{
if (WinServiceUninstall())
printf("Uninstalling service\n");
return 1;
}
else
{
printf("Runtime-Error: unsupported option %s", argv[c]);
usage(argv[0]);
return 1;
}
}
if (strcmp(argv[c], "--service") == 0)
WinServiceRun();
#endif
++c;
}
if (!sConfigMgr->LoadInitial(cfg_file))
{
printf("Invalid or missing configuration file : %s\n", cfg_file);
printf("Verify that the file exists and has \'[worldserver]' written in the top of the file!\n");
return 1;
}
sLog->outString("Using configuration file %s.", cfg_file);
sLog->outString("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
sLog->outString("Using ACE version: %s", ACE_VERSION);
///- and run the 'Master'
/// @todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd?
int ret = sMaster->Run();
// at sMaster return function exist with codes
// 0 - normal shutdown
// 1 - shutdown at error
// 2 - restart command used, this code can be used by restarter for restart Trinityd
return ret;
}
/// @}

View File

@@ -0,0 +1,505 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include <ace/Sig_Handler.h>
#include "Common.h"
#include "SystemConfig.h"
#include "SignalHandler.h"
#include "World.h"
#include "WorldRunnable.h"
#include "WorldSocket.h"
#include "WorldSocketMgr.h"
#include "Configuration/Config.h"
#include "Database/DatabaseEnv.h"
#include "Database/DatabaseWorkerPool.h"
#include "CliRunnable.h"
#include "Log.h"
#include "Master.h"
#include "RARunnable.h"
#include "TCSoap.h"
#include "Timer.h"
#include "Util.h"
#include "AuthSocket.h"
#include "RealmList.h"
#include "BigNumber.h"
#include "OpenSSLCrypto.h"
#ifdef _WIN32
#include "ServiceWin32.h"
extern int m_ServiceStatus;
#endif
#ifdef __linux__
#include <sched.h>
#include <sys/resource.h>
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
#endif
/// Handle worldservers's termination signals
class WorldServerSignalHandler : public Trinity::SignalHandler
{
public:
virtual void HandleSignal(int sigNum)
{
switch (sigNum)
{
case SIGINT:
World::StopNow(RESTART_EXIT_CODE);
break;
case SIGTERM:
#ifdef _WIN32
case SIGBREAK:
if (m_ServiceStatus != 1)
#endif
World::StopNow(SHUTDOWN_EXIT_CODE);
break;
/*case SIGSEGV:
sLog->outString("ZOMG! SIGSEGV handled!");
World::StopNow(SHUTDOWN_EXIT_CODE);
break;*/
}
}
};
class FreezeDetectorRunnable : public ACE_Based::Runnable
{
private:
uint32 _loops;
uint32 _lastChange;
uint32 _delayTime;
public:
FreezeDetectorRunnable(uint32 freezeDelay) : _loops(0), _lastChange(0), _delayTime(freezeDelay) {}
void run()
{
if (!_delayTime)
return;
sLog->outString("Starting up anti-freeze thread (%u seconds max stuck time)...", _delayTime/1000);
while (!World::IsStopped())
{
uint32 curtime = getMSTime();
if (_loops != World::m_worldLoopCounter)
{
_lastChange = curtime;
_loops = World::m_worldLoopCounter;
}
else if (getMSTimeDiff(_lastChange, curtime) > _delayTime)
{
sLog->outString("World Thread hangs, kicking out server!");
ASSERT(false);
}
ACE_Based::Thread::Sleep(1000);
}
sLog->outString("Anti-freeze thread exiting without problems.");
}
};
/// Main function
int Master::Run()
{
OpenSSLCrypto::threadsSetup();
BigNumber seed1;
seed1.SetRand(16 * 8);
sLog->outString("%s (worldserver-daemon)", _FULLVERSION);
sLog->outString("<Ctrl-C> to stop.\n");
/// worldserver PID file creation
std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
if (!pidFile.empty())
{
if (uint32 pid = CreatePIDFile(pidFile))
sLog->outString("Daemon PID: %u\n", pid);
else
{
sLog->outString("Cannot create PID file %s.\n", pidFile.c_str());
return 1;
}
}
///- Start the databases
if (!_StartDB())
return 1;
// set server offline (not connectable)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID);
///- Initialize the World
sWorld->SetInitialWorldSettings();
///- Initialize the signal handlers
WorldServerSignalHandler signalINT, signalTERM; //, signalSEGV
#ifdef _WIN32
WorldServerSignalHandler signalBREAK;
#endif /* _WIN32 */
///- Register worldserver's signal handlers
ACE_Sig_Handler handle;
handle.register_handler(SIGINT, &signalINT);
handle.register_handler(SIGTERM, &signalTERM);
#ifdef _WIN32
handle.register_handler(SIGBREAK, &signalBREAK);
#endif
//handle.register_handler(SIGSEGV, &signalSEGV);
///- Launch WorldRunnable thread
ACE_Based::Thread worldThread(new WorldRunnable);
worldThread.setPriority(ACE_Based::Highest);
ACE_Based::Thread* cliThread = NULL;
#ifdef _WIN32
if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
#else
if (sConfigMgr->GetBoolDefault("Console.Enable", true))
#endif
{
///- Launch CliRunnable thread
cliThread = new ACE_Based::Thread(new CliRunnable);
}
ACE_Based::Thread rarThread(new RARunnable);
// pussywizard:
ACE_Based::Thread auctionLising_thread(new AuctionListingRunnable);
auctionLising_thread.setPriority(ACE_Based::High);
#if defined(_WIN32) || defined(__linux__)
///- Handle affinity for multiple processors and process priority
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
#ifdef _WIN32 // Windows
HANDLE hProcess = GetCurrentProcess();
if (affinity > 0)
{
ULONG_PTR appAff;
ULONG_PTR sysAff;
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
{
ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors
if (!currentAffinity)
sLog->outError("Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff);
else if (SetProcessAffinityMask(hProcess, currentAffinity))
sLog->outString("Using processors (bitmask, hex): %x", currentAffinity);
else
sLog->outError("Can't set used processors (hex): %x", currentAffinity);
}
}
if (highPriority)
{
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
sLog->outString("worldserver process priority class set to HIGH");
else
sLog->outError("Can't set worldserver process priority class.");
}
#else // Linux
if (affinity > 0)
{
cpu_set_t mask;
CPU_ZERO(&mask);
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
if (affinity & (1 << i))
CPU_SET(i, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
sLog->outError("Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
else
{
CPU_ZERO(&mask);
sched_getaffinity(0, sizeof(mask), &mask);
sLog->outString("Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
}
}
if (highPriority)
{
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
sLog->outError("Can't set worldserver process priority class, error: %s", strerror(errno));
else
sLog->outString("worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
}
#endif
#endif
// Start soap serving thread
ACE_Based::Thread* soapThread = NULL;
if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
{
TCSoapRunnable* runnable = new TCSoapRunnable();
runnable->SetListenArguments(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878)));
soapThread = new ACE_Based::Thread(runnable);
}
// Start up freeze catcher thread
ACE_Based::Thread* freezeThread = NULL;
if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0))
{
FreezeDetectorRunnable* runnable = new FreezeDetectorRunnable(freezeDelay*1000);
freezeThread = new ACE_Based::Thread(runnable);
freezeThread->setPriority(ACE_Based::Highest);
}
///- Launch the world listener socket
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1)
{
sLog->outError("Failed to start network");
World::StopNow(ERROR_EXIT_CODE);
// go down and shutdown the server
}
// set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION);
// when the main thread closes the singletons get unloaded
// since worldrunnable uses them, it will crash if unloaded after master
worldThread.wait();
rarThread.wait();
auctionLising_thread.wait();
if (soapThread)
{
soapThread->wait();
soapThread->destroy();
delete soapThread;
}
if (freezeThread)
{
freezeThread->wait();
delete freezeThread;
}
// set server offline
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID);
///- Clean database before leaving
ClearOnlineAccounts();
_StopDB();
sLog->outString("Halting process...");
if (cliThread)
{
#ifdef _WIN32
// this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
//_exit(1);
// send keyboard input to safely unblock the CLI thread
INPUT_RECORD b[4];
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
b[0].EventType = KEY_EVENT;
b[0].Event.KeyEvent.bKeyDown = TRUE;
b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
b[0].Event.KeyEvent.wRepeatCount = 1;
b[1].EventType = KEY_EVENT;
b[1].Event.KeyEvent.bKeyDown = FALSE;
b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
b[1].Event.KeyEvent.wRepeatCount = 1;
b[2].EventType = KEY_EVENT;
b[2].Event.KeyEvent.bKeyDown = TRUE;
b[2].Event.KeyEvent.dwControlKeyState = 0;
b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[2].Event.KeyEvent.wRepeatCount = 1;
b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].EventType = KEY_EVENT;
b[3].Event.KeyEvent.bKeyDown = FALSE;
b[3].Event.KeyEvent.dwControlKeyState = 0;
b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
b[3].Event.KeyEvent.wRepeatCount = 1;
DWORD numb;
WriteConsoleInput(hStdIn, b, 4, &numb);
cliThread->wait();
#else
cliThread->destroy();
#endif
delete cliThread;
}
// for some unknown reason, unloading scripts here and not in worldrunnable
// fixes a memory leak related to detaching threads from the module
//UnloadScriptingModule();
OpenSSLCrypto::threadsCleanup();
// Exit the process with specified return value
return World::GetExitCode();
}
/// Initialize connection to the databases
bool Master::_StartDB()
{
MySQL::Library_Init();
sLog->SetLogDB(false);
std::string dbstring;
uint8 async_threads, synch_threads;
dbstring = sConfigMgr->GetStringDefault("WorldDatabaseInfo", "");
if (dbstring.empty())
{
sLog->outError("World database not specified in configuration file");
return false;
}
async_threads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1));
if (async_threads < 1 || async_threads > 32)
{
sLog->outError("World database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synch_threads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1));
///- Initialise the world database
if (!WorldDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog->outError("Cannot connect to world database %s", dbstring.c_str());
return false;
}
///- Get character database info from configuration file
dbstring = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", "");
if (dbstring.empty())
{
sLog->outError("Character database not specified in configuration file");
return false;
}
async_threads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1));
if (async_threads < 1 || async_threads > 32)
{
sLog->outError("Character database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synch_threads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2));
///- Initialise the Character database
if (!CharacterDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog->outError("Cannot connect to Character database %s", dbstring.c_str());
return false;
}
///- Get login database info from configuration file
dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
if (dbstring.empty())
{
sLog->outError("Login database not specified in configuration file");
return false;
}
async_threads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1));
if (async_threads < 1 || async_threads > 32)
{
sLog->outError("Login database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
synch_threads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1));
///- Initialise the login database
if (!LoginDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog->outError("Cannot connect to login database %s", dbstring.c_str());
return false;
}
///- Get the realm Id from the configuration file
realmID = sConfigMgr->GetIntDefault("RealmID", 0);
if (!realmID || realmID > 8) // pussywizard: above 8 spoils 8-bit online mask for the accounts
{
sLog->outError("Realm ID not defined in configuration file");
return false;
}
sLog->outString("Realm running as realm ID %d", realmID);
///- Initialize the DB logging system
sLog->SetRealmID(realmID);
///- Clean the database before starting
ClearOnlineAccounts();
///- Insert version info into DB
WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query
sWorld->LoadDBVersion();
sLog->outString("Using World DB: %s", sWorld->GetDBVersion());
return true;
}
void Master::_StopDB()
{
CharacterDatabase.Close();
WorldDatabase.Close();
LoginDatabase.Close();
MySQL::Library_End();
}
/// Clear 'online' status for all accounts with characters in this realm
void Master::ClearOnlineAccounts()
{
// Reset online status for all accounts with characters on the current realm
// pussywizard: tc query would set online=0 even if logged in on another realm >_>
LoginDatabase.DirectPExecute("UPDATE account SET online = online & ~(1<<(%u-1)) WHERE online & (1<<(%u-1))", realmID, realmID);
// Reset online status for all characters
CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef _MASTER_H
#define _MASTER_H
#include "Common.h"
/// Start the server
class Master
{
public:
int Run();
private:
bool _StartDB();
void _StopDB();
void ClearOnlineAccounts();
};
#define sMaster ACE_Singleton<Master, ACE_Null_Mutex>::instance()
#endif
/// @}

View File

@@ -0,0 +1 @@
#include "worldPCH.h"

View File

@@ -0,0 +1,8 @@
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
#include "Common.h"
#include "World.h"
#include "Log.h"
#include "Database/DatabaseEnv.h"
#include "Configuration/Config.h"
#include "Util.h"

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include "Common.h"
#include "Config.h"
#include "Log.h"
#include "RARunnable.h"
#include "World.h"
#include <ace/Reactor_Impl.h>
#include <ace/TP_Reactor.h>
#include <ace/Dev_Poll_Reactor.h>
#include <ace/Acceptor.h>
#include <ace/SOCK_Acceptor.h>
#include "RASocket.h"
RARunnable::RARunnable()
{
ACE_Reactor_Impl* imp;
#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
imp = new ACE_Dev_Poll_Reactor();
imp->max_notify_iterations (128);
imp->restart (1);
#else
imp = new ACE_TP_Reactor();
imp->max_notify_iterations (128);
#endif
m_Reactor = new ACE_Reactor (imp, 1);
}
RARunnable::~RARunnable()
{
delete m_Reactor;
}
void RARunnable::run()
{
if (!sConfigMgr->GetBoolDefault("Ra.Enable", false))
return;
ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor;
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
std::string stringIp = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
ACE_INET_Addr listenAddress(raPort, stringIp.c_str());
if (acceptor.open(listenAddress, m_Reactor) == -1)
{
sLog->outError("Trinity RA can not bind to port %d on %s", raPort, stringIp.c_str());
return;
}
sLog->outString("Starting Trinity RA on port %d on %s", raPort, stringIp.c_str());
while (!World::IsStopped())
{
ACE_Time_Value interval(0, 100000);
if (m_Reactor->run_reactor_event_loop(interval) == -1)
break;
}
;//sLog->outStaticDebug("Trinity RA thread exiting");
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef _TRINITY_RARUNNABLE_H_
#define _TRINITY_RARUNNABLE_H_
#include "Common.h"
#include <ace/Reactor.h>
class RARunnable : public ACE_Based::Runnable
{
public:
RARunnable();
virtual ~RARunnable();
void run();
private:
ACE_Reactor* m_Reactor;
};
#endif /* _TRINITY_RARUNNABLE_H_ */
/// @}

View File

@@ -0,0 +1,426 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include "Common.h"
#include "Configuration/Config.h"
#include "Database/DatabaseEnv.h"
#include "AccountMgr.h"
#include "Log.h"
#include "RASocket.h"
#include "Util.h"
#include "World.h"
#include "SHA1.h"
RASocket::RASocket()
{
_minLevel = uint8(sConfigMgr->GetIntDefault("RA.MinLevel", 3));
_commandExecuting = false;
}
int RASocket::open(void *)
{
ACE_INET_Addr remoteAddress;
if (peer().get_remote_addr(remoteAddress) == -1)
{
sLog->outError("RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno));
return -1;
}
sLog->outRemote("Incoming connection from %s", remoteAddress.get_host_addr());
return activate();
}
int RASocket::handle_close(ACE_HANDLE /*handle*/, ACE_Reactor_Mask /*mask*/)
{
sLog->outRemote("Closing connection");
peer().close_reader();
wait();
// While the above wait() will wait for the ::svc() to finish, it will not wait for the async event
// RASocket::commandfinished to be completed. Calling destroy() before the latter function ends
// will lead to using a freed pointer -> crash.
while (_commandExecuting.value())
ACE_OS::sleep(1);
destroy();
return 0;
}
int RASocket::send(const std::string& line)
{
#ifdef MSG_NOSIGNAL
ssize_t n = peer().send(line.c_str(), line.length(), MSG_NOSIGNAL);
#else
ssize_t n = peer().send(line.c_str(), line.length());
#endif // MSG_NOSIGNAL
return n == ssize_t(line.length()) ? 0 : -1;
}
int RASocket::recv_line(ACE_Message_Block& buffer)
{
char byte;
for (;;)
{
ssize_t n = peer().recv(&byte, sizeof(byte));
if (n < 0)
return -1;
if (n == 0)
{
// EOF, connection was closed
errno = ECONNRESET;
return -1;
}
ACE_ASSERT(n == sizeof(byte));
if (byte == '\n')
break;
else if (byte == '\r') /* Ignore CR */
continue;
else if (buffer.copy(&byte, sizeof(byte)) == -1)
return -1;
}
const char nullTerm = '\0';
if (buffer.copy(&nullTerm, sizeof(nullTerm)) == -1)
return -1;
return 0;
}
int RASocket::recv_line(std::string& out_line)
{
char buf[4096];
ACE_Data_Block db(sizeof (buf),
ACE_Message_Block::MB_DATA,
buf,
0,
0,
ACE_Message_Block::DONT_DELETE,
0);
ACE_Message_Block message_block(&db,
ACE_Message_Block::DONT_DELETE,
0);
if (recv_line(message_block) == -1)
{
sLog->outRemote("Recv error %s", ACE_OS::strerror(errno));
return -1;
}
out_line = message_block.rd_ptr();
return 0;
}
int RASocket::process_command(const std::string& command)
{
if (command.length() == 0)
return 0;
sLog->outRemote("Got command: %s", command.c_str());
// handle quit, exit and logout commands to terminate connection
if (command == "quit" || command == "exit" || command == "logout") {
(void) send("Bye\r\n");
return -1;
}
_commandExecuting = true;
CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished);
sWorld->QueueCliCommand(cmd);
// wait for result
ACE_Message_Block* mb;
for (;;)
{
if (getq(mb) == -1)
return -1;
if (mb->msg_type() == ACE_Message_Block::MB_BREAK)
{
mb->release();
break;
}
if (send(std::string(mb->rd_ptr(), mb->length())) == -1)
{
mb->release();
return -1;
}
mb->release();
}
return 0;
}
int RASocket::check_access_level(const std::string& user)
{
std::string safeUser = user;
AccountMgr::normalizeString(safeUser);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS);
stmt->setString(0, safeUser);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
sLog->outRemote("User %s does not exist in database", user.c_str());
return -1;
}
Field* fields = result->Fetch();
if (fields[1].GetUInt8() < _minLevel)
{
sLog->outRemote("User %s has no privilege to login", user.c_str());
return -1;
}
else if (fields[2].GetInt32() != -1)
{
sLog->outRemote("User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str());
return -1;
}
return 0;
}
int RASocket::check_password(const std::string& user, const std::string& pass)
{
std::string safe_user = user;
AccountMgr::normalizeString(safe_user);
std::string safe_pass = pass;
AccountMgr::normalizeString(safe_pass);
std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
stmt->setString(0, safe_user);
stmt->setString(1, hash);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
sLog->outRemote("Wrong password for user: %s", user.c_str());
return -1;
}
return 0;
}
int RASocket::authenticate()
{
if (send(std::string("Username: ")) == -1)
return -1;
std::string user;
if (recv_line(user) == -1)
return -1;
if (send(std::string("Password: ")) == -1)
return -1;
std::string pass;
if (recv_line(pass) == -1)
return -1;
sLog->outRemote("Login attempt for user: %s", user.c_str());
if (check_access_level(user) == -1)
return -1;
if (check_password(user, pass) == -1)
return -1;
sLog->outRemote("User login: %s", user.c_str());
return 0;
}
int RASocket::subnegotiate()
{
char buf[1024];
ACE_Data_Block db(sizeof (buf),
ACE_Message_Block::MB_DATA,
buf,
0,
0,
ACE_Message_Block::DONT_DELETE,
0);
ACE_Message_Block message_block(&db,
ACE_Message_Block::DONT_DELETE,
0);
const size_t recv_size = message_block.space();
// Wait a maximum of 1000ms for negotiation packet - not all telnet clients may send it
ACE_Time_Value waitTime = ACE_Time_Value(1);
const ssize_t n = peer().recv(message_block.wr_ptr(),
recv_size, &waitTime);
if (n <= 0)
return int(n);
if (n >= 1024)
{
sLog->outRemote("RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", uint32(n));
return -1;
}
buf[n] = '\0';
#ifdef _DEBUG
for (uint8 i = 0; i < n; )
{
uint8 iac = buf[i];
if (iac == 0xFF) // "Interpret as Command" (IAC)
{
uint8 command = buf[++i];
std::stringstream ss;
switch (command)
{
case 0xFB: // WILL
ss << "WILL ";
break;
case 0xFC: // WON'T
ss << "WON'T ";
break;
case 0xFD: // DO
ss << "DO ";
break;
case 0xFE: // DON'T
ss << "DON'T ";
break;
default:
return -1; // not allowed
}
uint8 param = buf[++i];
ss << uint32(param);
sLog->outRemote(ss.str().c_str());
}
++i;
}
#endif
//! Just send back end of subnegotiation packet
uint8 const reply[2] = {0xFF, 0xF0};
#ifdef MSG_NOSIGNAL
return int(peer().send(reply, 2, MSG_NOSIGNAL));
#else
return int(peer().send(reply, 2));
#endif // MSG_NOSIGNAL
}
int RASocket::svc(void)
{
//! Subnegotiation may differ per client - do not react on it
subnegotiate();
if (send("Authentication required\r\n") == -1)
return -1;
if (authenticate() == -1)
{
(void) send("Authentication failed\r\n");
return -1;
}
// send motd
if (send(std::string(sWorld->GetMotd()) + "\r\n") == -1)
return -1;
for (;;)
{
// show prompt
if (send("TC> ") == -1)
return -1;
std::string line;
if (recv_line(line) == -1)
return -1;
if (process_command(line) == -1)
return -1;
}
return 0;
}
void RASocket::zprint(void* callbackArg, const char * szText)
{
if (!szText || !callbackArg)
return;
RASocket* socket = static_cast<RASocket*>(callbackArg);
size_t sz = strlen(szText);
ACE_Message_Block* mb = new ACE_Message_Block(sz);
mb->copy(szText, sz);
ACE_Time_Value tv = ACE_Time_Value::zero;
if (socket->putq(mb, &tv) == -1)
{
sLog->outRemote("Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno));
mb->release();
}
}
void RASocket::commandFinished(void* callbackArg, bool /*success*/)
{
if (!callbackArg)
return;
RASocket* socket = static_cast<RASocket*>(callbackArg);
ACE_Message_Block* mb = new ACE_Message_Block();
mb->msg_type(ACE_Message_Block::MB_BREAK);
// the message is 0 size control message to tell that command output is finished
// hence we don't put timeout, because it shouldn't increase queue size and shouldn't block
if (socket->putq(mb->duplicate()) == -1)
{
// getting here is bad, command can't be marked as complete
//sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno));
}
mb->release();
socket->_commandExecuting = false;
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef _RASOCKET_H
#define _RASOCKET_H
#include "Common.h"
#include <ace/Synch_Traits.h>
#include <ace/Svc_Handler.h>
#include <ace/SOCK_Stream.h>
#include <ace/SOCK_Acceptor.h>
/// Remote Administration socket
class RASocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
{
public:
RASocket();
virtual ~RASocket() { }
virtual int svc();
virtual int open(void* = 0);
virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
private:
int recv_line(std::string& outLine);
int recv_line(ACE_Message_Block& buffer);
int process_command(const std::string& command);
int authenticate();
int subnegotiate(); ///< Used by telnet protocol RFC 854 / 855
int check_access_level(const std::string& user);
int check_password(const std::string& user, const std::string& pass);
int send(const std::string& line);
static void zprint(void* callbackArg, const char* szText);
static void commandFinished(void* callbackArg, bool success);
private:
uint8 _minLevel; ///< Minimum security level required to connect
ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting;
};
#endif
/// @}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TCSoap.h"
#include "soapH.h"
#include "soapStub.h"
void TCSoapRunnable::run()
{
struct soap soap;
soap_init(&soap);
soap_set_imode(&soap, SOAP_C_UTFSTRING);
soap_set_omode(&soap, SOAP_C_UTFSTRING);
// check every 3 seconds if world ended
soap.accept_timeout = 3;
soap.recv_timeout = 5;
soap.send_timeout = 5;
if (!soap_valid_socket(soap_bind(&soap, _host.c_str(), _port, 100)))
{
sLog->outError("TCSoap: couldn't bind to %s:%d", _host.c_str(), _port);
exit(-1);
}
sLog->outString("TCSoap: bound to http://%s:%d", _host.c_str(), _port);
while (!World::IsStopped())
{
if (!soap_valid_socket(soap_accept(&soap)))
continue; // ran into an accept timeout
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: accepted connection from IP=%d.%d.%d.%d", (int)(soap.ip>>24)&0xFF, (int)(soap.ip>>16)&0xFF, (int)(soap.ip>>8)&0xFF, (int)soap.ip&0xFF);
struct soap* thread_soap = soap_copy(&soap);// make a safe copy
ACE_Message_Block* mb = new ACE_Message_Block(sizeof(struct soap*));
ACE_OS::memcpy(mb->wr_ptr(), &thread_soap, sizeof(struct soap*));
process_message(mb);
}
soap_done(&soap);
}
void TCSoapRunnable::process_message(ACE_Message_Block* mb)
{
ACE_TRACE (ACE_TEXT ("SOAPWorkingThread::process_message"));
struct soap* soap;
ACE_OS::memcpy(&soap, mb->rd_ptr (), sizeof(struct soap*));
mb->release();
soap_serve(soap);
soap_destroy(soap); // dealloc C++ data
soap_end(soap); // dealloc data and clean up
soap_done(soap); // detach soap struct
free(soap);
}
/*
Code used for generating stubs:
int ns1__executeCommand(char* command, char** result);
*/
int ns1__executeCommand(soap* soap, char* command, char** result)
{
// security check
if (!soap->userid || !soap->passwd)
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: Client didn't provide login information");
return 401;
}
uint32 accountId = AccountMgr::GetId(soap->userid);
if (!accountId)
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: Client used invalid username '%s'", soap->userid);
return 401;
}
if (!AccountMgr::CheckPassword(accountId, soap->passwd))
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: invalid password for account '%s'", soap->userid);
return 401;
}
if (AccountMgr::GetSecurity(accountId) < SEC_ADMINISTRATOR)
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: %s's gmlevel is too low", soap->userid);
return 403;
}
if (!command || !*command)
return soap_sender_fault(soap, "Command can not be empty", "The supplied command was an empty string");
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: got command '%s'", command);
SOAPCommand connection;
// commands are executed in the world thread. We have to wait for them to be completed
{
// CliCommandHolder will be deleted from world, accessing after queueing is NOT save
CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished);
sWorld->QueueCliCommand(cmd);
}
// wait for callback to complete command
int acc = connection.pendingCommands.acquire();
if (acc)
{
sLog->outError("TCSoap: Error while acquiring lock, acc = %i, errno = %u", acc, errno);
}
// alright, command finished
char* printBuffer = soap_strdup(soap, connection.m_printBuffer.c_str());
if (connection.hasCommandSucceeded())
{
*result = printBuffer;
return SOAP_OK;
}
else
return soap_sender_fault(soap, printBuffer, printBuffer);
}
void SOAPCommand::commandFinished(void* soapconnection, bool success)
{
SOAPCommand* con = (SOAPCommand*)soapconnection;
con->setCommandSuccess(success);
con->pendingCommands.release();
}
////////////////////////////////////////////////////////////////////////////////
//
// Namespace Definition Table
//
////////////////////////////////////////////////////////////////////////////////
struct Namespace namespaces[] =
{ { "SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", NULL, NULL }, // must be first
{ "SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", NULL, NULL }, // must be second
{ "xsi", "http://www.w3.org/1999/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL },
{ "xsd", "http://www.w3.org/1999/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL },
{ "ns1", "urn:TC", NULL, NULL }, // "ns1" namespace prefix
{ NULL, NULL, NULL, NULL }
};

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TCSOAP_H
#define _TCSOAP_H
#include "Define.h"
#include "AccountMgr.h"
#include <ace/Semaphore.h>
#include <ace/Task.h>
#include <Threading.h>
class TCSoapRunnable : public ACE_Based::Runnable
{
public:
TCSoapRunnable() : _port(0) { }
void run();
void SetListenArguments(const std::string& host, uint16 port)
{
_host = host;
_port = port;
}
private:
void process_message(ACE_Message_Block* mb);
std::string _host;
uint16 _port;
};
class SOAPCommand
{
public:
SOAPCommand():
pendingCommands(0, USYNC_THREAD, "pendingCommands"), m_success(false)
{
}
~SOAPCommand()
{
}
void appendToPrintBuffer(const char* msg)
{
m_printBuffer += msg;
}
ACE_Semaphore pendingCommands;
void setCommandSuccess(bool val)
{
m_success = val;
}
bool hasCommandSucceeded() const
{
return m_success;
}
static void print(void* callbackArg, const char* msg)
{
((SOAPCommand*)callbackArg)->appendToPrintBuffer(msg);
}
static void commandFinished(void* callbackArg, bool success);
bool m_success;
std::string m_printBuffer;
};
#endif

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
\ingroup Trinityd
*/
#include "Common.h"
#include "ObjectAccessor.h"
#include "World.h"
#include "WorldSocketMgr.h"
#include "Database/DatabaseEnv.h"
#include "ScriptMgr.h"
#include "BattlegroundMgr.h"
#include "MapManager.h"
#include "Timer.h"
#include "WorldRunnable.h"
#include "OutdoorPvPMgr.h"
#include "AvgDiffTracker.h"
#include "AsyncAuctionListing.h"
#ifdef _WIN32
#include "ServiceWin32.h"
extern int m_ServiceStatus;
#endif
/// Heartbeat for the World
void WorldRunnable::run()
{
uint32 realCurrTime = 0;
uint32 realPrevTime = getMSTime();
sScriptMgr->OnStartup();
///- While we have not World::m_stopEvent, update the world
while (!World::IsStopped())
{
++World::m_worldLoopCounter;
realCurrTime = getMSTime();
uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
sWorld->Update( diff );
realPrevTime = realCurrTime;
uint32 executionTimeDiff = getMSTimeDiff(realCurrTime, getMSTime());
devDiffTracker.Update(executionTimeDiff);
avgDiffTracker.Update(executionTimeDiff > WORLD_SLEEP_CONST ? executionTimeDiff : WORLD_SLEEP_CONST);
if (executionTimeDiff < WORLD_SLEEP_CONST)
ACE_Based::Thread::Sleep(WORLD_SLEEP_CONST-executionTimeDiff);
#ifdef _WIN32
if (m_ServiceStatus == 0)
World::StopNow(SHUTDOWN_EXIT_CODE);
while (m_ServiceStatus == 2)
Sleep(1000);
#endif
}
sLog->SetLogDB(false);
sScriptMgr->OnShutdown();
sWorld->KickAll(); // save and kick all players
sWorld->UpdateSessions( 1 ); // real players unload required UpdateSessions call
// unload battleground templates before different singletons destroyed
sBattlegroundMgr->DeleteAllBattlegrounds();
sWorldSocketMgr->StopNetwork();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
sScriptMgr->Unload();
sOutdoorPvPMgr->Die();
}
void AuctionListingRunnable::run()
{
sLog->outString("Starting up Auction House Listing thread...");
while (!World::IsStopped())
{
if (AsyncAuctionListingMgr::IsAuctionListingAllowed())
{
uint32 diff = AsyncAuctionListingMgr::GetDiff();
AsyncAuctionListingMgr::ResetDiff();
if (AsyncAuctionListingMgr::GetTempList().size() || AsyncAuctionListingMgr::GetList().size())
{
TRINITY_GUARD(ACE_Thread_Mutex, AsyncAuctionListingMgr::GetLock());
{
TRINITY_GUARD(ACE_Thread_Mutex, AsyncAuctionListingMgr::GetTempLock());
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetTempList().begin(); itr != AsyncAuctionListingMgr::GetTempList().end(); ++itr)
AsyncAuctionListingMgr::GetList().push_back( (*itr) );
AsyncAuctionListingMgr::GetTempList().clear();
}
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
{
if ((*itr)._msTimer <= diff)
(*itr)._msTimer = 0;
else
(*itr)._msTimer -= diff;
}
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
if ((*itr)._msTimer == 0)
{
if ((*itr).Execute())
AsyncAuctionListingMgr::GetList().erase(itr);
break;
}
}
}
ACE_Based::Thread::Sleep(1);
}
sLog->outString("Auction House Listing thread exiting without problems.");
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// \addtogroup Trinityd
/// @{
/// \file
#ifndef __WORLDRUNNABLE_H
#define __WORLDRUNNABLE_H
/// Heartbeat thread for the World
class WorldRunnable : public ACE_Based::Runnable
{
public:
void run();
};
class AuctionListingRunnable : public ACE_Based::Runnable
{
public:
void run();
};
#endif
/// @}

View File

@@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by SunwellCore.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "resource.h"
#include "revision.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON ICON "worldserver.ico"
/////////////////////////////////////////////////////////////////////////////
// Neutre (Par défaut système) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
#ifdef _WIN32
LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifndef _DEBUG
FILEFLAGS 0
#else
#define VER_PRERELEASE VS_FF_PRERELEASE
#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
#define VER_DEBUG 0
FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080004b0"
BEGIN
VALUE "CompanyName", VER_COMPANYNAME_STR
VALUE "FileDescription", "World Server Daemon"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "worldserver"
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
VALUE "OriginalFilename", "worldserver.exe"
VALUE "ProductName", "World Server"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x800, 1200
END
END
#endif