aboutsummaryrefslogtreecommitdiff
path: root/src/server/worldserver
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/worldserver')
-rw-r--r--src/server/worldserver/CommandLine/CliRunnable.cpp445
-rw-r--r--src/server/worldserver/CommandLine/CliRunnable.h35
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.cpp265
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.h68
-rw-r--r--src/server/worldserver/WorldThread/WorldRunnable.cpp97
-rw-r--r--src/server/worldserver/WorldThread/WorldRunnable.h35
6 files changed, 945 insertions, 0 deletions
diff --git a/src/server/worldserver/CommandLine/CliRunnable.cpp b/src/server/worldserver/CommandLine/CliRunnable.cpp
new file mode 100644
index 00000000000..b39faf694db
--- /dev/null
+++ b/src/server/worldserver/CommandLine/CliRunnable.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup Trinityd
+/// @{
+/// \file
+
+#include "Common.h"
+#include "ObjectMgr.h"
+#include "World.h"
+#include "WorldSession.h"
+#include "Config/ConfigEnv.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 != 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;
+ matches = (char**)NULL;
+
+ if(start == 0)
+ matches = rl_completion_matches((char*)text,&command_finder);
+ else
+ rl_bind_key('\t',rl_abort);
+ return (matches);
+}
+#endif
+
+void utf8print(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
+{
+ va_list v;
+ vprintf(str, v);
+ va_end(v);
+ fflush(stdout);
+}
+#endif
+}
+
+/// Delete a user account and all associated characters in this realm
+/// \todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm, delete account chars in realm then delete account
+bool ChatHandler::HandleAccountDeleteCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ ///- Get the account name from the command line
+ char *account_name_str=strtok ((char*)args," ");
+ if (!account_name_str)
+ return false;
+
+ std::string account_name = account_name_str;
+ if(!AccountMgr::normalizeString(account_name))
+ {
+ PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 account_id = accmgr.GetId(account_name);
+ if(!account_id)
+ {
+ PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ /// Commands not recommended call from chat, but support anyway
+ /// can delete only for account with less security
+ /// This is also reject self apply in fact
+ if(HasLowerSecurityAccount (NULL,account_id,true))
+ return false;
+
+ AccountOpResult result = accmgr.DeleteAccount(account_id);
+ switch(result)
+ {
+ case AOR_OK:
+ PSendSysMessage(LANG_ACCOUNT_DELETED,account_name.c_str());
+ break;
+ case AOR_NAME_NOT_EXIST:
+ PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ case AOR_DB_INTERNAL_ERROR:
+ PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ default:
+ PSendSysMessage(LANG_ACCOUNT_NOT_DELETED,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+}
+
+bool ChatHandler::HandleCharacterDeleteCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char *character_name_str = strtok((char*)args," ");
+ if(!character_name_str)
+ return false;
+
+ std::string character_name = character_name_str;
+ if(!normalizePlayerName(character_name))
+ return false;
+
+ uint64 character_guid;
+ uint32 account_id;
+
+ Player *player = objmgr.GetPlayer(character_name.c_str());
+ if(player)
+ {
+ character_guid = player->GetGUID();
+ account_id = player->GetSession()->GetAccountId();
+ player->GetSession()->KickPlayer();
+ }
+ else
+ {
+ character_guid = objmgr.GetPlayerGUIDByName(character_name);
+ if(!character_guid)
+ {
+ PSendSysMessage(LANG_NO_PLAYER,character_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ account_id = objmgr.GetPlayerAccountIdByGUID(character_guid);
+ }
+
+ std::string account_name;
+ accmgr.GetName (account_id,account_name);
+
+ Player::DeleteFromDB(character_guid, account_id, true);
+ PSendSysMessage(LANG_CHARACTER_DELETED,character_name.c_str(),GUID_LOPART(character_guid),account_name.c_str(), account_id);
+ return true;
+}
+
+/// Exit the realm
+bool ChatHandler::HandleServerExitCommand(const char* /*args*/)
+{
+ SendSysMessage(LANG_COMMAND_EXIT);
+ World::StopNow(SHUTDOWN_EXIT_CODE);
+ return true;
+}
+
+/// Display info on users currently in the realm
+bool ChatHandler::HandleAccountOnlineListCommand(const char* /*args*/)
+{
+ ///- Get the list of accounts ID logged to the realm
+ QueryResult_AutoPtr resultDB = CharacterDatabase.Query("SELECT name,account,map,zone FROM characters WHERE online > 0");
+ if (!resultDB)
+ {
+ SendSysMessage(LANG_ACCOUNT_LIST_EMPTY);
+ return true;
+ }
+
+ ///- Display the list of account/characters online
+ SendSysMessage(LANG_ACCOUNT_LIST_BAR_HEADER);
+ SendSysMessage(LANG_ACCOUNT_LIST_HEADER);
+ SendSysMessage(LANG_ACCOUNT_LIST_BAR);
+
+ ///- Circle through accounts
+ do
+ {
+ Field *fieldsDB = resultDB->Fetch();
+ std::string name = fieldsDB[0].GetCppString();
+ uint32 account = fieldsDB[1].GetUInt32();
+
+ ///- Get the username, last IP and GM level of each account
+ // No SQL injection. account is uint32.
+ QueryResult_AutoPtr resultLogin =
+ LoginDatabase.PQuery("SELECT a.username, a.last_ip, aa.gmlevel, a.expansion "
+ "FROM account a "
+ "LEFT JOIN account_access aa "
+ "ON (a.id = aa.id) "
+ "WHERE a.id = '%u'", account);
+ if(resultLogin)
+ {
+ Field *fieldsLogin = resultLogin->Fetch();
+ PSendSysMessage(LANG_ACCOUNT_LIST_LINE,
+ fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsDB[2].GetInt32(),fieldsDB[3].GetInt32(),fieldsLogin[3].GetUInt32(),fieldsLogin[2].GetUInt32());
+ }
+ else
+ PSendSysMessage(LANG_ACCOUNT_LIST_ERROR,name.c_str());
+
+ }while(resultDB->NextRow());
+
+ SendSysMessage(LANG_ACCOUNT_LIST_BAR);
+ return true;
+}
+
+/// Create an account
+bool ChatHandler::HandleAccountCreateCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ ///- %Parse the command line arguments
+ char *szAcc = strtok((char*)args, " ");
+ char *szPassword = strtok(NULL, " ");
+ if(!szAcc || !szPassword)
+ return false;
+
+ // normalized in accmgr.CreateAccount
+ std::string account_name = szAcc;
+ std::string password = szPassword;
+
+ AccountOpResult result = accmgr.CreateAccount(account_name, password);
+ switch(result)
+ {
+ case AOR_OK:
+ PSendSysMessage(LANG_ACCOUNT_CREATED,account_name.c_str());
+ break;
+ case AOR_NAME_TOO_LONG:
+ SendSysMessage(LANG_ACCOUNT_TOO_LONG);
+ SetSentErrorMessage(true);
+ return false;
+ case AOR_NAME_ALREDY_EXIST:
+ SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ case AOR_DB_INTERNAL_ERROR:
+ PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ default:
+ PSendSysMessage(LANG_ACCOUNT_NOT_CREATED,account_name.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+}
+
+/// Set the level of logging
+bool ChatHandler::HandleServerSetLogFileLevelCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ char *NewLevel = strtok((char*)args, " ");
+ if (!NewLevel)
+ return false;
+
+ sLog.SetLogFileLevel(NewLevel);
+ return true;
+}
+
+/// Set the level of logging
+bool ChatHandler::HandleServerSetLogLevelCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ char *NewLevel = strtok((char*)args, " ");
+ if (!NewLevel)
+ return false;
+
+ sLog.SetLogLevel(NewLevel);
+ return true;
+}
+
+/// set diff time record interval
+bool ChatHandler::HandleServerSetDiffTimeCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ char *NewTimeStr = strtok((char*)args, " ");
+ if(!NewTimeStr)
+ return false;
+
+ int32 NewTime =atoi(NewTimeStr);
+ if(NewTime < 0)
+ return false;
+
+ sWorld.SetRecordDiffInterval(NewTime);
+ printf( "Record diff every %u ms\n", NewTime);
+ return true;
+}
+
+/// @}
+
+#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()
+{
+ ///- Init new SQL thread for the world database (one connection call enough)
+ WorldDatabase.ThreadStart(); // let thread do safe mySQL requests
+
+ char commandbuf[256];
+
+ ///- Display the list of available CLI functions then beep
+ sLog.outString("");
+ #if PLATFORM != WINDOWS
+ rl_attempted_completion_function = cli_completion;
+ #endif
+ if(sConfig.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 == WINDOWS
+ 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 == WINDOWS
+ printf("TC>");
+ #endif
+ continue;
+ }
+
+ std::string command;
+ if(!consoleToUtf8(command_str,command)) // convert from console encoding to utf8
+ {
+ #if PLATFORM == WINDOWS
+ printf("TC>");
+ #endif
+ continue;
+ }
+ fflush(stdout);
+ sWorld.QueueCliCommand(&utf8print,command.c_str());
+ #if PLATFORM != WINDOWS
+ add_history(command.c_str());
+ #endif
+
+ }
+ else if (feof(stdin))
+ {
+ World::StopNow(SHUTDOWN_EXIT_CODE);
+ }
+
+ }
+
+ ///- End the database thread
+ WorldDatabase.ThreadEnd(); // free mySQL thread resources
+}
diff --git a/src/server/worldserver/CommandLine/CliRunnable.h b/src/server/worldserver/CommandLine/CliRunnable.h
new file mode 100644
index 00000000000..9f990b2b469
--- /dev/null
+++ b/src/server/worldserver/CommandLine/CliRunnable.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup Trinityd
+/// @{
+/// \file
+
+#ifndef __CLIRUNNABLE_H
+#define __CLIRUNNABLE_H
+
+/// Command Line Interface handling thread
+class CliRunnable : public ACE_Based::Runnable
+{
+ public:
+ void run();
+};
+#endif
+/// @}
diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp
new file mode 100644
index 00000000000..32c16d9980f
--- /dev/null
+++ b/src/server/worldserver/RemoteAccess/RASocket.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup Trinityd
+*/
+
+#include "Common.h"
+#include "Config/ConfigEnv.h"
+#include "Database/DatabaseEnv.h"
+#include "AccountMgr.h"
+#include "Log.h"
+#include "RASocket.h"
+#include "Util.h"
+#include "World.h"
+
+/// \todo Make this thread safe if in the future 2 admins should be able to log at the same time.
+SOCKET r;
+
+#define dropclient {Sendf("I'm busy right now, come back later."); \
+ SetCloseAndDelete(); \
+ return; \
+ }
+
+uint32 iSession=0; ///< Session number (incremented each time a new connection is made)
+unsigned int iUsers=0; ///< Number of active administrators
+
+typedef int(* pPrintf)(const char*,...);
+
+void ParseCommand(CliCommandHolder::Print*, char*command);
+
+/// RASocket constructor
+RASocket::RASocket(ISocketHandler &h): TcpSocket(h)
+{
+
+ ///- Increment the session number
+ iSess =iSession++ ;
+
+ ///- Get the config parameters
+ bSecure = sConfig.GetBoolDefault( "RA.Secure", true );
+ iMinLevel = sConfig.GetIntDefault( "RA.MinLevel", 3 );
+
+ ///- Initialize buffer and data
+ iInputLength=0;
+ buff=new char[RA_BUFF_SIZE];
+ stage=NONE;
+}
+
+/// RASocket destructor
+RASocket::~RASocket()
+{
+ ///- Delete buffer and decrease active admins count
+ delete [] buff;
+
+ sLog.outRemote("Connection was closed.\n");
+
+ if(stage==OK)
+ iUsers--;
+}
+
+/// Accept an incoming connection
+void RASocket::OnAccept()
+{
+ std::string ss=GetRemoteAddress();
+ sLog.outRemote("Incoming connection from %s.\n",ss.c_str());
+ ///- If there is already an active admin, drop the connection
+ if(iUsers)
+ dropclient
+
+ ///- Else print Motd
+ Sendf("%s\r\n",sWorld.GetMotd());
+}
+
+/// Read data from the network
+void RASocket::OnRead()
+{
+ ///- Read data and check input length
+ TcpSocket::OnRead();
+
+ unsigned int sz=ibuf.GetLength();
+ if(iInputLength+sz>=RA_BUFF_SIZE)
+ {
+ sLog.outRemote("Input buffer overflow, possible DOS attack.\n");
+ SetCloseAndDelete();
+ return;
+ }
+
+ ///- If there is already an active admin (other than you), drop the connection
+ if(stage!=OK && iUsers)
+ dropclient
+
+ char *inp = new char [sz+1];
+ ibuf.Read(inp,sz);
+
+ /// \todo Can somebody explain this 'Linux bugfix'?
+ if(stage==NONE)
+ if(sz>4) //linux remote telnet
+ if(memcmp(inp ,"USER ",5))
+ {
+ delete [] inp;return;
+ printf("lin bugfix");
+ } //linux bugfix
+
+ ///- Discard data after line break or line feed
+ bool gotenter=false;
+ unsigned int y=0;
+ for (; y<sz; y++)
+ if(inp[y]=='\r'||inp[y]=='\n')
+ {
+ gotenter=true;
+ break;
+ }
+
+ //No buffer overflow (checked above)
+ memcpy(&buff[iInputLength],inp,y);
+ iInputLength+=y;
+ delete [] inp;
+ if(gotenter)
+ {
+
+ buff[iInputLength]=0;
+ iInputLength=0;
+ switch(stage)
+ {
+ /// <ul> <li> If the input is 'USER <username>'
+ case NONE:
+ if(!memcmp(buff,"USER ",5)) //got "USER" cmd
+ {
+ szLogin=&buff[5];
+
+ ///- Get the password from the account table
+ std::string login = szLogin;
+
+ ///- Convert Account name to Upper Format
+ AccountMgr::normalizeString(login);
+
+ ///- Escape the Login to allow quotes in names
+ LoginDatabase.escape_string(login);
+
+ QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = '%s'",login.c_str ());
+
+ ///- If the user is not found, deny access
+ if(!result)
+ {
+ Sendf("-No such user.\r\n");
+ sLog.outRemote("User %s does not exist.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ else
+ {
+ Field *fields = result->Fetch();
+
+ //szPass=fields[0].GetString();
+
+ ///- if gmlevel is too low, deny access
+ if(fields[1].GetUInt32()<iMinLevel || fields[1].GetUInt32() == NULL)
+ {
+ Sendf("-Not enough privileges.\r\n");
+ sLog.outRemote("User %s has no privilege.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ else if(fields[2].GetInt32() != -1)
+ {
+ ///- if RealmID isn't -1, deny access
+ Sendf("-Not enough privileges.\r\n");
+ sLog.outRemote("User %s has to be assigned on all realms (with RealmID = '-1').\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ else
+ {
+ stage=LG;
+ }
+ }
+ }
+ break;
+ ///<li> If the input is 'PASS <password>' (and the user already gave his username)
+ case LG:
+ if(!memcmp(buff,"PASS ",5)) //got "PASS" cmd
+ { //login+pass ok
+ ///- If password is correct, increment the number of active administrators
+ std::string login = szLogin;
+ std::string pw = &buff[5];
+
+ AccountMgr::normalizeString(login);
+ AccountMgr::normalizeString(pw);
+ LoginDatabase.escape_string(login);
+ LoginDatabase.escape_string(pw);
+
+ QueryResult_AutoPtr check = LoginDatabase.PQuery(
+ "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))",
+ login.c_str(), login.c_str(), pw.c_str());
+
+ if(check)
+ {
+ r=GetSocket();
+ stage=OK;
+ ++iUsers;
+
+ Sendf("+Logged in.\r\n");
+ sLog.outRemote("User %s has logged in.\n",szLogin.c_str());
+ Sendf("TC>");
+ }
+ else
+ {
+ ///- Else deny access
+ Sendf("-Wrong pass.\r\n");
+ sLog.outRemote("User %s has failed to log in.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ }
+ break;
+ ///<li> If user is logged, parse and execute the command
+ case OK:
+ if(strlen(buff))
+ {
+ sLog.outRemote("Got '%s' cmd.\n",buff);
+ sWorld.QueueCliCommand(&RASocket::zprint , buff);
+ }
+ else
+ Sendf("TC>");
+ break;
+ ///</ul>
+ };
+
+ }
+}
+
+/// Output function
+void RASocket::zprint( const char * szText )
+{
+ if( !szText )
+ return;
+
+ #ifdef RA_CRYPT
+
+ char *megabuffer=strdup(szText);
+ unsigned int sz=strlen(megabuffer);
+ Encrypt(megabuffer,sz);
+ send(r,megabuffer,sz,0);
+ delete [] megabuffer;
+
+ #else
+
+ unsigned int sz=strlen(szText);
+ send(r,szText,sz,0);
+
+ #endif
+}
diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h
new file mode 100644
index 00000000000..5c13724f90d
--- /dev/null
+++ b/src/server/worldserver/RemoteAccess/RASocket.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup Trinityd
+/// @{
+/// \file
+
+#ifndef _RASOCKET_H
+#define _RASOCKET_H
+
+#include "sockets/TcpSocket.h"
+
+#include "Common.h"
+
+#define RA_BUFF_SIZE 1024
+
+class ISocketHandler;
+
+/// Remote Administration socket
+class RASocket: public TcpSocket
+{
+ public:
+
+ RASocket(ISocketHandler& h);
+ ~RASocket();
+
+ void OnAccept();
+ void OnRead();
+
+ private:
+
+ char * buff;
+ std::string szLogin;
+ uint32 iSess;
+ unsigned int iInputLength;
+ bool bLog;
+ bool bSecure; //kick on wrong pass, non exist. user, user with no priv
+ //will protect from DOS, bruteforce attacks
+ //some 'smart' protection must be added for more security
+ uint8 iMinLevel;
+ enum
+ {
+ NONE, //initial value
+ LG, //only login was entered
+ OK, //both login and pass were given, and they are correct and user have enough priv.
+ }stage;
+
+ static void zprint( const char * szText );
+};
+#endif
+/// @}
diff --git a/src/server/worldserver/WorldThread/WorldRunnable.cpp b/src/server/worldserver/WorldThread/WorldRunnable.cpp
new file mode 100644
index 00000000000..c674ddbc06f
--- /dev/null
+++ b/src/server/worldserver/WorldThread/WorldRunnable.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup Trinityd
+*/
+
+#include "Common.h"
+#include "ObjectAccessor.h"
+#include "World.h"
+#include "WorldSocketMgr.h"
+#include "Database/DatabaseEnv.h"
+
+#include "BattleGroundMgr.h"
+#include "MapManager.h"
+#include "Timer.h"
+#include "WorldRunnable.h"
+
+#define WORLD_SLEEP_CONST 50
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+extern int m_ServiceStatus;
+#endif
+
+/// Heartbeat for the World
+void WorldRunnable::run()
+{
+ ///- Init new SQL thread for the world database
+ WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough)
+
+ sWorld.InitResultQueue();
+
+ uint32 realCurrTime = 0;
+ uint32 realPrevTime = getMSTime();
+
+ uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
+
+ ///- 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;
+
+ // diff (D0) include time of previous sleep (d0) + tick time (t0)
+ // we want that next d1 + t1 == WORLD_SLEEP_CONST
+ // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
+ // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
+ if (diff <= WORLD_SLEEP_CONST+prevSleepTime)
+ {
+ prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff;
+ ACE_Based::Thread::Sleep(prevSleepTime);
+ }
+ else
+ prevSleepTime = 0;
+
+ #ifdef WIN32
+ if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE);
+ while (m_ServiceStatus == 2) Sleep(1000);
+ #endif
+ }
+
+ 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();
+
+ MapManager::Instance().UnloadAll(); // unload all grids (including locked in memory)
+
+ ///- End the database thread
+ WorldDatabase.ThreadEnd(); // free mySQL thread resources
+}
diff --git a/src/server/worldserver/WorldThread/WorldRunnable.h b/src/server/worldserver/WorldThread/WorldRunnable.h
new file mode 100644
index 00000000000..f14ee021f36
--- /dev/null
+++ b/src/server/worldserver/WorldThread/WorldRunnable.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup Trinityd
+/// @{
+/// \file
+
+#ifndef __WORLDRUNNABLE_H
+#define __WORLDRUNNABLE_H
+
+/// Heartbeat thread for the World
+class WorldRunnable : public ACE_Based::Runnable
+{
+ public:
+ void run();
+};
+#endif
+/// @}