svn -> git Migration

This commit is contained in:
KimLS
2013-02-16 16:14:39 -08:00
parent 88c9715fb0
commit da7347f76f
1174 changed files with 445622 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(eqlaunch_sources
eqlaunch.cpp
worldserver.cpp
ZoneLaunch.cpp
)
SET(eqlaunch_headers
worldserver.h
ZoneLaunch.h
)
ADD_EXECUTABLE(eqlaunch ${eqlaunch_sources} ${eqlaunch_headers})
TARGET_LINK_LIBRARIES(eqlaunch Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE})
IF(MSVC)
SET_TARGET_PROPERTIES(eqlaunch PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
TARGET_LINK_LIBRARIES(eqlaunch "Ws2_32.lib")
ENDIF(MSVC)
IF(MINGW)
TARGET_LINK_LIBRARIES(eqlaunch "WS2_32")
ENDIF(MINGW)
IF(UNIX)
TARGET_LINK_LIBRARIES(eqlaunch "dl")
TARGET_LINK_LIBRARIES(eqlaunch "z")
TARGET_LINK_LIBRARIES(eqlaunch "m")
TARGET_LINK_LIBRARIES(eqlaunch "rt")
TARGET_LINK_LIBRARIES(eqlaunch "pthread")
ADD_DEFINITIONS(-fPIC)
ENDIF(UNIX)
SET(EXECUTABLE_OUTPUT_PATH ../Bin)
+287
View File
@@ -0,0 +1,287 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ZoneLaunch.h"
#include "worldserver.h"
#include "../common/EQEmuConfig.h"
//static const uint32 ZONE_RESTART_DELAY = 10000;
//static const uint32 ZONE_TERMINATE_WAIT = 10000;
int ZoneLaunch::s_running = 0; //the number of zones running under this launcher
Timer ZoneLaunch::s_startTimer(1); //I do not trust this things state after static initialization
void ZoneLaunch::InitStartTimer() {
s_startTimer.Start(1);
s_startTimer.Trigger();
}
ZoneLaunch::ZoneLaunch(WorldServer *world, const char *launcher_name,
const char *zone_name, const EQEmuConfig *config)
: m_state(StateStartPending),
m_world(world),
m_zone(zone_name),
m_launcherName(launcher_name),
m_config(config),
m_timer(config->RestartWait),
m_ref(ProcLauncher::ProcError),
m_startCount(0),
m_killFails(0)
{
//trigger the startup timer initially so it boots the first time.
m_timer.Trigger();
}
ZoneLaunch::~ZoneLaunch() {
if(IsRunning())
s_running--;
}
void ZoneLaunch::SendStatus() const {
m_world->SendStatus(m_zone.c_str(), m_startCount, IsRunning());
}
void ZoneLaunch::Start() {
ProcLauncher::Spec *spec = new ProcLauncher::Spec();
spec->program = m_config->ZoneExe;
// if(m_zone.substr(0,7) == "dynamic")
// spec->args.push_back(".");
// else
spec->args.push_back(m_zone);
spec->args.push_back(m_launcherName);
spec->handler = this;
spec->logFile = m_config->LogPrefix + m_zone + m_config->LogSuffix;
//spec is consumed, even on failure
m_ref = ProcLauncher::get()->Launch(spec);
if(m_ref == ProcLauncher::ProcError) {
_log(LAUNCHER__ERROR, "Failure to launch '%s %s %s'. ", m_config->ZoneExe.c_str(), m_zone.c_str(), m_launcherName);
m_timer.Start(m_config->RestartWait);
return;
}
m_startCount++;
m_state = StateStarted;
s_running++;
m_killFails = 0;
SendStatus();
_log(LAUNCHER__STATUS, "Zone %s has been started.", m_zone.c_str());
}
void ZoneLaunch::Restart() {
switch(m_state) {
case StateRestartPending:
_log(LAUNCHER__STATUS, "Restart of zone %s requested when a restart is already pending.", m_zone.c_str());
break;
case StateStartPending:
//we havent started yet, do nothing
_log(LAUNCHER__STATUS, "Restart of %s before it has started. Ignoring.", m_zone.c_str());
break;
case StateStarted:
//process is running along, kill it off..
if(m_ref == ProcLauncher::ProcError)
break; //we have no proc ref... cannot stop..
if(!ProcLauncher::get()->Terminate(m_ref, true)) {
//failed to terminate the process, its not likely that it will work if we try again, so give up.
_log(LAUNCHER__ERROR, "Failed to terminate zone %s. Giving up and moving to stopped.", m_zone.c_str());
m_state = StateStopped;
break;
}
_log(LAUNCHER__STATUS, "Termination signal sent to zone %s.", m_zone.c_str());
m_timer.Start(m_config->TerminateWait);
m_state = StateRestartPending;
break;
case StateStopPending:
_log(LAUNCHER__STATUS, "Restart of zone %s requested when a stop is pending. Ignoring.", m_zone.c_str());
break;
case StateStopped:
//process is already stopped... nothing to do..
_log(LAUNCHER__STATUS, "Restart requested when zone %s is already stopped.", m_zone.c_str());
break;
}
}
void ZoneLaunch::Stop(bool graceful) {
switch(m_state) {
case StateStartPending:
//we havent started yet, transition directly to stopped.
_log(LAUNCHER__STATUS, "Stopping zone %s before it has started.", m_zone.c_str());
m_state = StateStopped;
break;
case StateStarted:
case StateRestartPending:
case StateStopPending:
if(m_ref == ProcLauncher::ProcError)
break; //we have no proc ref... cannot stop..
if(!ProcLauncher::get()->Terminate(m_ref, graceful)) {
//failed to terminate the process, its not likely that it will work if we try again, so give up.
_log(LAUNCHER__ERROR, "Failed to terminate zone %s. Giving up and moving to stopped.", m_zone.c_str());
m_state = StateStopped;
break;
}
_log(LAUNCHER__STATUS, "Termination signal sent to zone %s.", m_zone.c_str());
m_timer.Start(m_config->TerminateWait);
m_state = StateStopPending;
break;
case StateStopped:
//process is already stopped... nothing to do..
_log(LAUNCHER__STATUS, "Stop requested when zone %s is already stopped.", m_zone.c_str());
break;
}
}
bool ZoneLaunch::Process() {
switch(m_state) {
case StateStartPending:
if(m_timer.Check(false)) {
//our internal timer says its time to start. Check with the shared timer.
if(!s_startTimer.Check(false)) {
//we have to wait on the shared timer now..
break;
}
//ok, both timers say we can start.
//disable our internal timer, will get started again if it is needed.
m_timer.Disable();
//actually start up the program
_log(LAUNCHER__STATUS, "Starting zone %s", m_zone.c_str());
Start();
//now update the shared timer to reflect the proper start interval.
if(s_running == 1) {
//we are the first zone started. wait that interval.
_log(LAUNCHER__STATUS, "Waiting %d milliseconds before booting the second zone.", m_config->InitialBootWait);
s_startTimer.Start(m_config->InitialBootWait);
} else {
//just some follow on zone, use that interval.
_log(LAUNCHER__STATUS, "Waiting %d milliseconds before booting the next zone.", m_config->ZoneBootInterval);
s_startTimer.Start(m_config->ZoneBootInterval);
}
} //else, timer still ticking, keep waiting
break;
case StateStarted:
//happy state, do nothing..
break;
case StateRestartPending:
//waiting for notification that our child has died..
if(m_timer.Check()) {
//we have timed out, try to kill the child again
_log(LAUNCHER__STATUS, "Zone %s refused to die, killing again.", m_zone.c_str());
Restart();
}
break;
case StateStopPending:
//waiting for notification that our child has died..
if(m_timer.Check()) {
//we have timed out, try to kill the child again
m_killFails++;
if(m_killFails > 5) { //should get this number from somewhere..
_log(LAUNCHER__STATUS, "Zone %s refused to die, giving up and acting like its dead.", m_zone.c_str());
m_state = StateStopped;
s_running--;
SendStatus();
} else {
_log(LAUNCHER__STATUS, "Zone %s refused to die, killing again.", m_zone.c_str());
Stop(false);
}
}
break;
case StateStopped:
//signal our caller to remove us
return(false);
break;
}
return(true);
}
//called when the process actually dies off...
void ZoneLaunch::OnTerminate(const ProcLauncher::ProcRef &ref, const ProcLauncher::Spec *spec) {
s_running--;
switch(m_state) {
case StateStartPending:
_log(LAUNCHER__STATUS, "Zone %s has gone down before we started it..?? Restart timer started.", m_zone.c_str());
m_state = StateStartPending;
m_timer.Start(m_config->RestartWait);
break;
case StateStarted:
//something happened to our happy process...
_log(LAUNCHER__STATUS, "Zone %s has gone down. Restart timer started.", m_zone.c_str());
m_state = StateStartPending;
m_timer.Start(m_config->RestartWait);
break;
case StateRestartPending:
//it finally died, start it on up again
_log(LAUNCHER__STATUS, "Zone %s has terminated. Transitioning to starting state.", m_zone.c_str());
m_state = StateStartPending;
break;
case StateStopPending:
//it finally died, transition to close.
_log(LAUNCHER__STATUS, "Zone %s has terminated. Transitioning to stopped state.", m_zone.c_str());
m_state = StateStopped;
break;
case StateStopped:
//we already thought it was stopped... dont care...
_log(LAUNCHER__STATUS, "Notified of zone %s terminating when we thought it was stopped.", m_zone.c_str());
break;
}
SendStatus();
}
+87
View File
@@ -0,0 +1,87 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ZONELAUNCH_H_
#define ZONELAUNCH_H_
#include "../common/ProcLauncher.h"
#include "../common/timer.h"
#include <string>
class WorldServer;
class EQEmuConfig;
class ZoneLaunch : protected ProcLauncher::EventHandler {
public:
ZoneLaunch(WorldServer *world, const char *launcher_name,
const char *zone_name, const EQEmuConfig *config);
virtual ~ZoneLaunch();
void Stop(bool graceful = true);
void Restart();
bool Process();
void SendStatus() const;
const char *GetZone() const { return(m_zone.c_str()); }
uint32 GetStartCount() const { return(m_startCount); }
//should only be called during process init to setup the start timer.
static void InitStartTimer();
protected:
bool IsRunning() const { return(m_state == StateStarted || m_state == StateStopPending || m_state == StateRestartPending); }
void Start();
void OnTerminate(const ProcLauncher::ProcRef &ref, const ProcLauncher::Spec *spec);
enum {
StateStartPending,
StateStarted,
StateRestartPending,
StateStopPending,
StateStopped
} m_state;
WorldServer *const m_world;
const std::string m_zone;
const char *const m_launcherName;
const EQEmuConfig *const m_config;
Timer m_timer;
ProcLauncher::ProcRef m_ref;
uint32 m_startCount;
uint32 m_killFails;
private:
static int s_running;
static Timer s_startTimer;
};
#endif /*ZONELAUNCH_H_*/
+207
View File
@@ -0,0 +1,207 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "../common/ProcLauncher.h"
#include "../common/EQEmuConfig.h"
#include "../common/servertalk.h"
#include "../common/platform.h"
#include "../common/crash.h"
#include "worldserver.h"
#include "ZoneLaunch.h"
#include <vector>
#include <map>
#include <set>
#include <signal.h>
#include <time.h>
using namespace std;
bool RunLoops = false;
void CatchSignal(int sig_num);
int main(int argc, char *argv[]) {
RegisterExecutablePlatform(ExePlatformLaunch);
set_exception_handler();
string launcher_name;
if(argc == 2) {
launcher_name = argv[1];
}
if(launcher_name.length() < 1) {
_log(LAUNCHER__ERROR, "You must specfify a launcher name as the first argument to this program.");
return(1);
}
_log(LAUNCHER__INIT, "Loading server configuration..");
if (!EQEmuConfig::LoadConfig()) {
_log(LAUNCHER__ERROR, "Loading server configuration failed.");
return(1);
}
const EQEmuConfig *Config = EQEmuConfig::get();
/*
* Setup nice signal handlers
*/
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
_log(LAUNCHER__ERROR, "Could not set signal handler");
return 1;
}
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
_log(LAUNCHER__ERROR, "Could not set signal handler");
return 1;
}
#ifndef WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
_log(LAUNCHER__ERROR, "Could not set signal handler");
return 1;
}
/*
* Add '.' to LD_LIBRARY_PATH
*/
//the storage passed to putenv must remain valid... crazy unix people
const char *pv = getenv("LD_LIBRARY_PATH");
if(pv == NULL) {
putenv(strdup("LD_LIBRARY_PATH=."));
} else {
char *v = (char *) malloc(strlen(pv) + 19);
sprintf(v, "LD_LIBRARY_PATH=.:%s", pv);
putenv(v);
}
#endif
map<string, ZoneLaunch *> zones;
WorldServer world(zones, launcher_name.c_str(), Config);
if (!world.Connect()) {
_log(LAUNCHER__ERROR, "worldserver.Connect() FAILED! Will retry.");
}
map<string, ZoneLaunch *>::iterator zone, zend;
set<string> to_remove;
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
_log(LAUNCHER__INIT, "Starting main loop...");
// zones["test"] = new ZoneLaunch(&world, "./zone", "dynamic_1");
ProcLauncher *launch = ProcLauncher::get();
RunLoops = true;
while(RunLoops) {
//Advance the timer to our current point in time
Timer::SetCurrentTime();
/*
* Process the world connection
*/
world.Process();
/*
* Let the process manager look for dead children
*/
launch->Process();
/*
* Give all zones a chance to process.
*/
zone = zones.begin();
zend = zones.end();
for(; zone != zend; zone++) {
if(!zone->second->Process())
to_remove.insert(zone->first);
}
/*
* Kill off any zones which have stopped
*/
while(!to_remove.empty()) {
string rem = *to_remove.begin();
to_remove.erase(rem);
zone = zones.find(rem);
if(zone == zones.end()) {
//wtf...
continue;
}
delete zone->second;
zones.erase(rem);
}
if (InterserverTimer.Check()) {
if (world.TryReconnect() && (!world.Connected()))
world.AsyncConnect();
}
/*
* Take a nice nap until next cycle
*/
if(zones.empty())
Sleep(5000);
else
Sleep(2000);
}
//try to be semi-nice about this... without waiting too long
zone = zones.begin();
zend = zones.end();
for(; zone != zend; zone++) {
zone->second->Stop();
}
Sleep(1);
launch->Process();
launch->TerminateAll(false);
Sleep(1);
launch->Process();
//kill anybody left
launch->TerminateAll(true);
for(; zone != zend; zone++) {
delete zone->second;
}
return(0);
}
void CatchSignal(int sig_num) {
_log(LAUNCHER__STATUS, "Caught signal %d", sig_num);
RunLoops = false;
}
+155
View File
@@ -0,0 +1,155 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "worldserver.h"
#include "../common/servertalk.h"
#include "ZoneLaunch.h"
#include "../common/EQEmuConfig.h"
WorldServer::WorldServer(map<string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config)
: WorldConnection(EmuTCPConnection::packetModeLauncher, config->SharedKey.c_str()),
m_name(name),
m_config(config),
m_zones(zones)
{
}
WorldServer::~WorldServer() {
}
void WorldServer::OnConnected() {
WorldConnection::OnConnected();
ServerPacket* pack = new ServerPacket(ServerOP_LauncherConnectInfo, sizeof(LauncherConnectInfo));
LauncherConnectInfo* sci = (LauncherConnectInfo*) pack->pBuffer;
strn0cpy(sci->name, m_name, sizeof(sci->name));
// sci->port = net.GetZonePort();
// strcpy(sci->address, net.GetZoneAddress());
SendPacket(pack);
safe_delete(pack);
//send status for all zones...
std::map<std::string, ZoneLaunch *>::iterator cur, end;
cur = m_zones.begin();
end = m_zones.end();
for(; cur != end; cur++) {
cur->second->SendStatus();
}
}
void WorldServer::Process() {
WorldConnection::Process();
if (!Connected())
return;
ServerPacket *pack = 0;
while((pack = tcpc.PopPacket())) {
switch(pack->opcode) {
case 0: {
break;
}
case ServerOP_EmoteMessage:
case ServerOP_KeepAlive: {
// ignore this
break;
}
case ServerOP_ZAAuthFailed: {
_log(LAUNCHER__ERROR, "World server responded 'Not Authorized', disabling reconnect");
pTryReconnect = false;
Disconnect();
break;
}
case ServerOP_LauncherZoneRequest: {
if(pack->size != sizeof(LauncherZoneRequest)) {
_log(LAUNCHER__NET, "Invalid size of LauncherZoneRequest: %d", pack->size);
break;
}
const LauncherZoneRequest *lzr = (const LauncherZoneRequest *) pack->pBuffer;
switch(ZoneRequestCommands(lzr->command)) {
case ZR_Start: {
if(m_zones.find(lzr->short_name) != m_zones.end()) {
_log(LAUNCHER__ERROR, "World told us to start zone %s, but it is already running.", lzr->short_name);
} else {
_log(LAUNCHER__WORLD, "World told us to start zone %s.", lzr->short_name);
ZoneLaunch *l = new ZoneLaunch(this, m_name, lzr->short_name, m_config);
m_zones[lzr->short_name] = l;
}
break;
}
case ZR_Restart: {
map<string, ZoneLaunch *>::iterator res = m_zones.find(lzr->short_name);
if(res == m_zones.end()) {
_log(LAUNCHER__ERROR, "World told us to restart zone %s, but it is not running.", lzr->short_name);
} else {
_log(LAUNCHER__WORLD, "World told us to restart zone %s.", lzr->short_name);
res->second->Restart();
}
break;
}
case ZR_Stop: {
map<string, ZoneLaunch *>::iterator res = m_zones.find(lzr->short_name);
if(res == m_zones.end()) {
_log(LAUNCHER__ERROR, "World told us to stop zone %s, but it is not running.", lzr->short_name);
} else {
_log(LAUNCHER__WORLD, "World told us to stop zone %s.", lzr->short_name);
res->second->Stop();
}
break;
}
}
break;
}
case ServerOP_GroupIDReply: {
//ignore this, world is still being dumb
break;
}
default: {
_log(LAUNCHER__NET, "Unknown opcode 0x%x from World of len %d", pack->opcode, pack->size);
//DumpPacket(pack->pBuffer, pack->size);
break;
}
}
safe_delete(pack);
}
}
void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool running) {
ServerPacket* pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus));
LauncherZoneStatus* it =(LauncherZoneStatus*) pack->pBuffer;
strn0cpy(it->short_name, short_name, 32);
it->start_count = start_count;
it->running = running?1:0;
SendPacket(pack);
safe_delete(pack);
}
+46
View File
@@ -0,0 +1,46 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WORLDSERVER_H
#define WORLDSERVER_H
#include "../common/worldconn.h"
#include <string>
#include <queue>
#include <map>
class ZoneLaunch;
class EQEmuConfig;
class WorldServer : public WorldConnection {
public:
WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config);
virtual ~WorldServer();
virtual void Process();
void SendStatus(const char *short_name, uint32 start_count, bool running);
private:
virtual void OnConnected();
const char *const m_name;
const EQEmuConfig *const m_config;
std::map<std::string, ZoneLaunch *> &m_zones;
};
#endif