* rewrote the realm/world login code.
-> reconnecting does work now, finally. * updated conf setting: reconnect=0: dont reconnect; reconnect=X: reconnect after X msecs. * misc code cleanups, crash fixes, and overall improved stability. * splitted RealmSocket into a RealmSession and the original RealmSocket code. better read-/useabilty because now its handled as WorldSession and related.
This commit is contained in:
parent
95353eb132
commit
6c4ae79a87
@ -17,7 +17,10 @@ debug=0
|
||||
exitonerror=0
|
||||
|
||||
// reconnect on failure/disconnect
|
||||
reconnect=0
|
||||
// 0 = dont't reconnect
|
||||
// everything else: delay (in ms) until the next connection attempt.
|
||||
// default: 5000 ms (5 secs)
|
||||
reconnect=5000
|
||||
|
||||
// 0 - show none
|
||||
// 1 - show only known/handled
|
||||
@ -33,13 +36,14 @@ showopcodes=3
|
||||
hidefreqopcodes=1
|
||||
|
||||
|
||||
// the IP or hostname the wow server is running on
|
||||
// the IP or hostname the realm server is running on
|
||||
realmlist=localhost
|
||||
|
||||
// port on which the realm server is listening (default=3724)
|
||||
realmport=3724
|
||||
|
||||
// PseuWoW will login on this realm
|
||||
// Case sensitive!
|
||||
realmname=My WoW Realm
|
||||
|
||||
// your account name
|
||||
@ -48,8 +52,9 @@ accname=test
|
||||
// your account password
|
||||
accpass=test
|
||||
|
||||
// the character name PseuWoW should choose to enter the world
|
||||
charname=PseuWoW
|
||||
// the character name PseuWoW should choose to enter the world.
|
||||
// case sensitive!
|
||||
charname=Pseuwow
|
||||
|
||||
|
||||
// Client emulation configuration
|
||||
@ -104,3 +109,4 @@ enablegui=0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ name=Shaman
|
||||
name=Mage
|
||||
|
||||
[9]
|
||||
name=Paladin
|
||||
name=Warlock
|
||||
|
||||
[10]
|
||||
name=UNKNOWN CLASS(10)
|
||||
|
||||
@ -30,7 +30,8 @@ DefScriptPackage::DefScriptPackage()
|
||||
|
||||
DefScriptPackage::~DefScriptPackage()
|
||||
{
|
||||
delete _eventmgr;
|
||||
if(_eventmgr)
|
||||
delete _eventmgr;
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ DefReturnResult DefScriptPackage::SCpause(CmdSet& Set){
|
||||
}
|
||||
|
||||
DefReturnResult DefScriptPackage::SCSendChatMessage(CmdSet& Set){
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCSendChatMessage: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -88,7 +88,7 @@ DefReturnResult DefScriptPackage::SCSendChatMessage(CmdSet& Set){
|
||||
DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){
|
||||
((PseuInstance*)parentMethod)->SaveAllCache();
|
||||
std::stringstream str;
|
||||
if(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid())
|
||||
if(((PseuInstance*)parentMethod)->GetWSession())
|
||||
{
|
||||
str << "Cache saved. [ ";
|
||||
str << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize();
|
||||
@ -105,7 +105,7 @@ DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){
|
||||
DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){
|
||||
if(Set.defaultarg.empty())
|
||||
return false;
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCEmote: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -141,7 +141,7 @@ DefReturnResult DefScriptPackage::SCfollow(CmdSet& Set)
|
||||
DefReturnResult DefScriptPackage::SCjoinchannel(CmdSet& Set){
|
||||
if(Set.defaultarg.empty())
|
||||
return false;
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCjoinchannel: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -153,7 +153,7 @@ DefReturnResult DefScriptPackage::SCjoinchannel(CmdSet& Set){
|
||||
DefReturnResult DefScriptPackage::SCleavechannel(CmdSet& Set){
|
||||
if(Set.defaultarg.empty())
|
||||
return false;
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCleavechannel: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -214,7 +214,7 @@ DefReturnResult DefScriptPackage::SCcastspell(CmdSet& Set)
|
||||
{
|
||||
if(Set.defaultarg.empty())
|
||||
return false;
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCcastspell: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -236,7 +236,7 @@ DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set){
|
||||
if(!id)
|
||||
return false;
|
||||
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCqueryitem: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -250,7 +250,7 @@ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set)
|
||||
// TODO: special targets: _self _pet _nearest ...
|
||||
DefReturnResult r;
|
||||
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCtarget: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -360,7 +360,7 @@ DefReturnResult DefScriptPackage::SCGetScpValue(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCGetPlayerGuid(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCGetPlayerGuid: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -380,7 +380,7 @@ DefReturnResult DefScriptPackage::SCGetPlayerGuid(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCGetName(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCGetName: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -411,7 +411,7 @@ DefReturnResult DefScriptPackage::SCGetName(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCGetEntry(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCGetEntry: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -433,7 +433,7 @@ DefReturnResult DefScriptPackage::SCGetEntry(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCGetObjectType(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCGetObjectType: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -455,7 +455,7 @@ DefReturnResult DefScriptPackage::SCGetObjectType(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCObjectKnown(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCObjectIsKnown: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
@ -489,7 +489,7 @@ DefReturnResult DefScriptPackage::SCGetScriptPerm(CmdSet& Set)
|
||||
|
||||
DefReturnResult DefScriptPackage::SCGetItemProtoValue(CmdSet& Set)
|
||||
{
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
||||
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||
{
|
||||
logerror("Invalid Script call: SCGetItemProtoValue: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#include "DefScriptInterface.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "DefScript/DefScript.h"
|
||||
#include "Realm/RealmSocket.h"
|
||||
#include "World/WorldSession.h"
|
||||
#include "RealmSession.h"
|
||||
#include "WorldSession.h"
|
||||
#include "CacheHandler.h"
|
||||
#include "GUI/PseuGUI.h"
|
||||
|
||||
@ -56,7 +56,7 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run)
|
||||
_stop=false;
|
||||
_fastquit=false;
|
||||
_startrealm=true;
|
||||
createWorldSession=false;
|
||||
_createws=false;
|
||||
_error=false;
|
||||
_initialized=false;
|
||||
|
||||
@ -65,15 +65,20 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run)
|
||||
|
||||
PseuInstance::~PseuInstance()
|
||||
{
|
||||
delete _wsession;
|
||||
if(GetConf()->enablecli && _cli)
|
||||
if(_cli)
|
||||
{
|
||||
_cli->stop();
|
||||
}
|
||||
|
||||
if(_rsession)
|
||||
delete _rsession;
|
||||
if(_wsession)
|
||||
delete _wsession;
|
||||
|
||||
delete _scp;
|
||||
delete _conf;
|
||||
//delete _rsession; // deleted by SocketHandler!!!!!
|
||||
log_close();
|
||||
delete _conf;
|
||||
|
||||
log_close();
|
||||
|
||||
}
|
||||
|
||||
@ -181,50 +186,50 @@ bool PseuInstance::Init(void) {
|
||||
|
||||
void PseuInstance::Run(void)
|
||||
{
|
||||
do
|
||||
|
||||
if(!_initialized)
|
||||
return;
|
||||
|
||||
if(GetConf()->realmlist.empty() || GetConf()->realmport==0)
|
||||
{
|
||||
if(!_initialized)
|
||||
return;
|
||||
logcritical("Realmlist address not set, can't connect.");
|
||||
SetError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// for now: create the realmsession only on startup.
|
||||
// may be extended to a script command later on.
|
||||
// then try to connect
|
||||
_rsession = new RealmSession(this);
|
||||
_rsession->Connect();
|
||||
_rsession->SendLogonChallenge();
|
||||
|
||||
if(GetConf()->realmlist.empty() || GetConf()->realmport==0)
|
||||
{
|
||||
logcritical("Realmlist address not set, can't connect.");
|
||||
SetError();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
_rsession=new RealmSocket(_sh);
|
||||
_rsession->SetDeleteByHandler();
|
||||
_rsession->SetHost(GetConf()->realmlist);
|
||||
_rsession->SetPort(GetConf()->realmport);
|
||||
_rsession->SetInstance(this);
|
||||
_rsession->Start();
|
||||
|
||||
if(_rsession->IsValid())
|
||||
{
|
||||
_sh.Add(_rsession);
|
||||
_sh.Select(1,0);
|
||||
}
|
||||
_startrealm=false; // the realm is started now
|
||||
|
||||
while( (!_stop) && (!_startrealm) )
|
||||
// this is the mainloop
|
||||
while(!_stop)
|
||||
{
|
||||
Update();
|
||||
if(_error)
|
||||
_stop=true;
|
||||
}
|
||||
}
|
||||
while(GetConf()->reconnect && (!_stop));
|
||||
|
||||
|
||||
}
|
||||
|
||||
// fastquit is defined if we clicked [X] (on windows)
|
||||
if(_fastquit)
|
||||
{
|
||||
log("Aborting Instance...");
|
||||
return;
|
||||
}
|
||||
|
||||
log("Shutting down instance...");
|
||||
|
||||
SaveAllCache();
|
||||
// if there was an error, better dont save, as the data might be damaged
|
||||
if(!_error)
|
||||
{
|
||||
SaveAllCache();
|
||||
//...
|
||||
}
|
||||
|
||||
if(GetConf()->exitonerror == false && _error)
|
||||
{
|
||||
@ -238,45 +243,49 @@ void PseuInstance::Run(void)
|
||||
|
||||
void PseuInstance::Update()
|
||||
{
|
||||
if(_sh.GetCount())
|
||||
// delete sessions if they are no longer needed
|
||||
if(_rsession && _rsession->MustDie())
|
||||
{
|
||||
_sh.Select(0,0); // update the realmsocket
|
||||
if(deleterealm)
|
||||
{
|
||||
deleterealm=false;
|
||||
_rsession = NULL; // was deleted by SocketHandler already!
|
||||
}
|
||||
delete _rsession;
|
||||
_rsession = NULL;
|
||||
}
|
||||
|
||||
if(createWorldSession && (!_wsession))
|
||||
if(_wsession && _wsession->MustDie())
|
||||
{
|
||||
createWorldSession=false;
|
||||
_wsession=new WorldSession(this);
|
||||
delete _wsession;
|
||||
_wsession = NULL;
|
||||
}
|
||||
if(_wsession && !_wsession->IsValid())
|
||||
|
||||
if(_createws)
|
||||
{
|
||||
_createws = false;
|
||||
if(_wsession)
|
||||
delete _wsession;
|
||||
_wsession = new WorldSession(this);
|
||||
_wsession->Start();
|
||||
}
|
||||
if(_wsession && _wsession->IsValid())
|
||||
|
||||
// if we have no active sessions, we may reconnect
|
||||
if((!_rsession) && (!_wsession) && GetConf()->reconnect)
|
||||
{
|
||||
try
|
||||
{
|
||||
_wsession->Update(); // update the worldSESSION, which will update the worldsocket itself
|
||||
}
|
||||
catch (...)
|
||||
logdetail("Waiting %u ms before reconnecting.",GetConf()->reconnect);
|
||||
for(uint32 t = 0; t < GetConf()->reconnect && !this->Stopped(); t+=100) Sleep(100);
|
||||
this->Sleep(1000); // wait 1 sec before reconnecting
|
||||
_rsession = new RealmSession(this);
|
||||
_rsession->Connect();
|
||||
_rsession->SendLogonChallenge(); // and login again
|
||||
}
|
||||
|
||||
// update currently existing/active sessions
|
||||
if(_rsession)
|
||||
_rsession->Update();
|
||||
if(_wsession)
|
||||
try { _wsession->Update(); } catch (...)
|
||||
{
|
||||
logerror("Unhandled exception in WorldSession::Update()");
|
||||
}
|
||||
|
||||
}
|
||||
if(_wsession && _wsession->DeleteMe())
|
||||
{
|
||||
delete _wsession;
|
||||
_wsession=NULL;
|
||||
_startrealm=true;
|
||||
this->Sleep(1000); // wait 1 sec before reconnecting
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GetScripts()->GetEventMgr()->Update();
|
||||
|
||||
this->Sleep(GetConf()->networksleeptime);
|
||||
@ -285,7 +294,7 @@ void PseuInstance::Update()
|
||||
void PseuInstance::SaveAllCache(void)
|
||||
{
|
||||
//...
|
||||
if(GetWSession() && GetWSession()->IsValid())
|
||||
if(GetWSession())
|
||||
{
|
||||
GetWSession()->plrNameCache.SaveToFile();
|
||||
ItemProtoCache_WriteDataToCache(GetWSession());
|
||||
@ -311,7 +320,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
|
||||
accname=v.Get("ACCNAME");
|
||||
accpass=v.Get("ACCPASS");
|
||||
exitonerror=(bool)atoi(v.Get("EXITONERROR").c_str());
|
||||
reconnect=(bool)atoi(v.Get("RECONNECT").c_str());
|
||||
reconnect=atoi(v.Get("RECONNECT").c_str());
|
||||
realmport=atoi(v.Get("REALMPORT").c_str());
|
||||
clientversion_string=v.Get("CLIENTVERSION");
|
||||
clientbuild=atoi(v.Get("CLIENTBUILD").c_str());
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#include "Network/SocketHandler.h"
|
||||
#include "SCPDatabase.h"
|
||||
|
||||
class RealmSocket;
|
||||
class RealmSession;
|
||||
class WorldSession;
|
||||
class Sockethandler;
|
||||
class PseuInstanceRunnable;
|
||||
@ -30,7 +30,7 @@ class PseuInstanceConf
|
||||
std::string accname;
|
||||
std::string accpass;
|
||||
bool exitonerror;
|
||||
bool reconnect;
|
||||
uint32 reconnect;
|
||||
uint16 realmport;
|
||||
uint16 worldport;
|
||||
uint8 clientversion[3];
|
||||
@ -67,7 +67,7 @@ class PseuInstance
|
||||
|
||||
|
||||
WorldSession *GetWSession(void) { return _wsession; }
|
||||
RealmSocket *GetRSession(void) { return _rsession; }
|
||||
RealmSession *GetRSession(void) { return _rsession; }
|
||||
PseuInstanceConf *GetConf(void) { return _conf; }
|
||||
DefScriptPackage *GetScripts(void) { return _scp; }
|
||||
PseuInstanceRunnable *GetRunnable(void) { return _runnable; }
|
||||
@ -82,19 +82,19 @@ class PseuInstance
|
||||
bool Init();
|
||||
void SaveAllCache(void);
|
||||
void Stop(void) { _stop = true; }
|
||||
bool Stopped(void) { return _stop; }
|
||||
void SetFastQuit(bool q=true) { _fastquit=true; }
|
||||
void Quit(void);
|
||||
void Run(void);
|
||||
void Update(void);
|
||||
void Sleep(uint32 msecs);
|
||||
|
||||
bool createWorldSession;
|
||||
bool deleterealm;
|
||||
void CreateWorldSession(void) { _createws = true; }
|
||||
|
||||
private:
|
||||
|
||||
PseuInstanceRunnable *_runnable;
|
||||
RealmSocket *_rsession;
|
||||
RealmSession *_rsession;
|
||||
WorldSession *_wsession;
|
||||
PseuInstanceConf *_conf;
|
||||
DefScriptPackage *_scp;
|
||||
@ -103,6 +103,7 @@ class PseuInstance
|
||||
bool _stop,_fastquit;
|
||||
bool _startrealm;
|
||||
bool _error;
|
||||
bool _createws;
|
||||
BigNumber _sessionkey;
|
||||
char *_ver,*_ver_short;
|
||||
SocketHandler _sh;
|
||||
|
||||
489
src/Client/Realm/RealmSession.cpp
Normal file
489
src/Client/Realm/RealmSession.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
#include "common.h"
|
||||
#include "Auth/Sha1.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "PseuWoW.h"
|
||||
#include "RealmSocket.h"
|
||||
#include "RealmSession.h"
|
||||
|
||||
enum AuthCmd
|
||||
{
|
||||
AUTH_LOGON_CHALLENGE = 0x00,
|
||||
AUTH_LOGON_PROOF = 0x01,
|
||||
REALM_LIST = 0x10,
|
||||
};
|
||||
|
||||
struct SRealmHeader
|
||||
{
|
||||
uint8 cmd; // OP code = CMD_REALM_LIST
|
||||
uint16 size; // size of the rest of packet, without this part
|
||||
uint32 unknown; // 0x00 00 00 00
|
||||
uint8 count; // quantity of realms
|
||||
};
|
||||
|
||||
struct SRealmInfo
|
||||
{
|
||||
uint8 icon; // icon near realm
|
||||
uint8 locked; // added in 2.0.x
|
||||
uint8 color; // color of record
|
||||
std::string name; // Text zero terminated name of Realm
|
||||
std::string addr_port; // Text zero terminated address of Realm ("ip:port")
|
||||
float population; // 1.6 -> population value. lower == lower population and vice versa
|
||||
uint8 chars_here; // number of characters on this server
|
||||
uint8 timezone; // timezone
|
||||
uint8 unknown; //
|
||||
};
|
||||
|
||||
struct AuthHandler
|
||||
{
|
||||
uint32 cmd;
|
||||
void (RealmSession::*handler)(ByteBuffer&);
|
||||
};
|
||||
|
||||
struct sAuthLogonChallenge_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 unk2;
|
||||
uint8 B[32];
|
||||
uint8 g_len;
|
||||
uint8 g[1];
|
||||
uint8 N_len;
|
||||
uint8 N[32];
|
||||
uint8 salt[32];
|
||||
uint8 unk3[16];
|
||||
};
|
||||
|
||||
struct sAuthLogonProof_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
uint32 unk2;
|
||||
};
|
||||
|
||||
RealmSession::RealmSession(PseuInstance* instance)
|
||||
{
|
||||
_instance = instance;
|
||||
_socket = NULL;
|
||||
_mustdie = false;
|
||||
_sh.SetAutoCloseSockets(false);
|
||||
}
|
||||
|
||||
RealmSession::~RealmSession()
|
||||
{
|
||||
// drop the socket
|
||||
ClearSocket();
|
||||
|
||||
// clear the queue
|
||||
ByteBuffer *packet;
|
||||
while(!pktQueue.empty())
|
||||
{
|
||||
packet = pktQueue.next();
|
||||
delete packet;
|
||||
}
|
||||
memset(_m2,0,20);
|
||||
_key=0;
|
||||
}
|
||||
|
||||
void RealmSession::Connect(void)
|
||||
{
|
||||
ClearSocket();
|
||||
_socket = new RealmSocket(_sh);
|
||||
_socket->SetSession(this);
|
||||
_socket->Open(GetInstance()->GetConf()->realmlist,GetInstance()->GetConf()->realmport);
|
||||
_sh.Add(_socket);
|
||||
_sh.Select(3,0);
|
||||
}
|
||||
|
||||
void RealmSession::ClearSocket(void)
|
||||
{
|
||||
if(_socket)
|
||||
{
|
||||
delete _socket;
|
||||
_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void RealmSession::SetMustDie(void)
|
||||
{
|
||||
_mustdie = true;
|
||||
}
|
||||
|
||||
bool RealmSession::MustDie(void)
|
||||
{
|
||||
return _mustdie;
|
||||
}
|
||||
|
||||
AuthHandler *RealmSession::_GetAuthHandlerTable(void) const
|
||||
{
|
||||
static AuthHandler table[] =
|
||||
{
|
||||
{AUTH_LOGON_CHALLENGE,&RealmSession::_HandleLogonChallenge},
|
||||
{AUTH_LOGON_PROOF,&RealmSession::_HandleLogonProof},
|
||||
{REALM_LIST,&RealmSession::_HandleRealmList},
|
||||
{0,NULL}
|
||||
};
|
||||
return table;
|
||||
}
|
||||
|
||||
void RealmSession::AddToPktQueue(ByteBuffer *pkt)
|
||||
{
|
||||
pktQueue.add(pkt);
|
||||
}
|
||||
|
||||
void RealmSession::Update(void)
|
||||
{
|
||||
AuthHandler *table = _GetAuthHandlerTable();
|
||||
ByteBuffer *pkt;
|
||||
uint8 cmd;
|
||||
|
||||
if( _sh.GetCount() )
|
||||
{
|
||||
_sh.Select(0,0);
|
||||
}
|
||||
|
||||
while(pktQueue.size())
|
||||
{
|
||||
pkt = pktQueue.next();
|
||||
cmd = (*pkt)[0];
|
||||
for(uint8 i=0;table[i].handler!=NULL;i++)
|
||||
{
|
||||
if(table[i].cmd==cmd)
|
||||
{
|
||||
(this->*table[i].handler)(*pkt);
|
||||
if(pkt->rpos() < pkt->size())
|
||||
{
|
||||
uint32 len = pkt->size() - pkt->rpos();
|
||||
uint8 *data = new uint8[len];
|
||||
pkt->read(data,len); // if we have data crap left on the buf, delete it
|
||||
logdebug("Data left on RealmSocket, Hexdump:");
|
||||
logdebug(toHexDump(data,len).c_str());
|
||||
delete [] data;
|
||||
}
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
PseuInstance *RealmSession::GetInstance(void)
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void RealmSession::_HandleRealmList(ByteBuffer& pkt)
|
||||
{
|
||||
std::string realmAddr;
|
||||
|
||||
uint32 unk;
|
||||
uint16 len,count;
|
||||
uint8 cmd;
|
||||
pkt >> cmd >> len >> unk >> count;
|
||||
|
||||
// no realm?
|
||||
if(count==0)
|
||||
return;
|
||||
|
||||
// alloc space for as many realms as needed
|
||||
SRealmInfo *realms=new SRealmInfo[count];
|
||||
|
||||
// readout realms
|
||||
for(uint8 i=0;i<count;i++)
|
||||
{
|
||||
pkt >> realms[i].icon;
|
||||
pkt >> realms[i].locked;
|
||||
pkt >> realms[i].color;
|
||||
pkt >> realms[i].name;
|
||||
pkt >> realms[i].addr_port;
|
||||
pkt >> realms[i].population;
|
||||
pkt >> realms[i].chars_here;
|
||||
pkt >> realms[i].timezone;
|
||||
pkt >> realms[i].unknown;
|
||||
}
|
||||
|
||||
// the rest of the packet is not interesting
|
||||
|
||||
for(uint8 i=0;i<count;i++)
|
||||
{
|
||||
if(realms[i].name==GetInstance()->GetConf()->realmname)
|
||||
{
|
||||
realmAddr=realms[i].addr_port;
|
||||
}
|
||||
logcustom(0,LGREEN,"Realm: %s (%s)",realms[i].name.c_str(),realms[i].addr_port.c_str());
|
||||
logdetail(" [chars:%d][population:%f][timezone:%d]",realms[i].chars_here,realms[i].population,realms[i].timezone);
|
||||
}
|
||||
delete [] realms;
|
||||
|
||||
// now setup where the worldserver is and how to login there
|
||||
if(realmAddr.empty()){
|
||||
log("Realm \"%s\" was not found on the realmlist!",GetInstance()->GetConf()->realmname.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// transform "hostname:port" into something useful
|
||||
// -> convert the worldserver port from string to int
|
||||
// -> write it into the config & set appropriate vars
|
||||
|
||||
uint16 colonpos=realmAddr.find(":");
|
||||
GetInstance()->GetConf()->worldhost=realmAddr.substr(0,colonpos);
|
||||
GetInstance()->GetConf()->worldport=atoi(realmAddr.substr(colonpos+1,realmAddr.length()-colonpos-1).c_str());
|
||||
// set vars
|
||||
GetInstance()->GetScripts()->variables.Set("WORLDHOST",GetInstance()->GetConf()->worldhost);
|
||||
GetInstance()->GetScripts()->variables.Set("WORLDPORT",toString((uint64)(GetInstance()->GetConf()->worldport)));
|
||||
|
||||
// now we have the correct addr/port, time to create the WorldSession
|
||||
GetInstance()->CreateWorldSession(); // will be done at next PseuInstance::Update()
|
||||
}
|
||||
|
||||
void RealmSession::SendLogonChallenge(void)
|
||||
{
|
||||
if( GetInstance()->GetConf()->accname.empty() || GetInstance()->GetConf()->clientversion_string.empty()
|
||||
|| GetInstance()->GetConf()->clientbuild==0 || GetInstance()->GetConf()->clientlang.empty() )
|
||||
{
|
||||
logcritical("Missing data, can't send Login to Realm Server!");
|
||||
GetInstance()->SetError();
|
||||
return;
|
||||
}
|
||||
std::string acc = stringToUpper(GetInstance()->GetConf()->accname);
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)AUTH_LOGON_CHALLENGE;
|
||||
packet << (uint8)2;
|
||||
packet << (uint8)(acc.length()+30); // length of the rest of the packet
|
||||
packet << (uint8)0;
|
||||
packet.append("WOW",3);
|
||||
packet.append(GetInstance()->GetConf()->clientversion,3); // 1.12.2 etc
|
||||
packet << (uint8)0;
|
||||
packet << (uint16)(GetInstance()->GetConf()->clientbuild); // (uint16) 5875
|
||||
packet << "68x" << "niW"; // "x86" - platform; "Win" - Operating system; both reversed and zero terminated
|
||||
for(uint8 i=0;i<4;i++)
|
||||
packet << (uint8)(GetInstance()->GetConf()->clientlang[3-i]); // "enUS" -> "SUne" : reversed and NOT zero terminated
|
||||
packet << (uint32)0x3c; // timezone
|
||||
packet << (uint32)_socket->GetClientRemoteAddr(); // my IP address
|
||||
packet << (uint8)acc.length(); // length of acc name without \0
|
||||
packet.append(acc.c_str(),acc.length()); // append accname, skip \0
|
||||
|
||||
SendRealmPacket(packet);
|
||||
|
||||
}
|
||||
|
||||
void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
|
||||
{
|
||||
logdebug("RealmSocket: Got AUTH_LOGON_CHALLENGE [%u of %u bytes]",pkt.size(),sizeof(sAuthLogonChallenge_S));
|
||||
if(pkt.size() < sizeof(sAuthLogonChallenge_S))
|
||||
{
|
||||
logerror("AUTH_LOGON_CHALLENGE: Recieved incorrect/unknown packet. Hexdump:");
|
||||
DumpInvalidPacket(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
sAuthLogonChallenge_S lc;
|
||||
pkt.read((uint8*)&lc, sizeof(sAuthLogonChallenge_S));
|
||||
|
||||
switch (lc.error)
|
||||
{
|
||||
case 4:
|
||||
log("Realm Server did not find account \"%s\"!",GetInstance()->GetConf()->accname.c_str());
|
||||
break;
|
||||
case 6:
|
||||
log("Account \"%s\" is already logged in!",GetInstance()->GetConf()->accname.c_str());
|
||||
// TODO: wait a certain amount of time before reconnecting? conf option?
|
||||
break;
|
||||
case 9:
|
||||
log("Realm Server doesn't accept this version!");
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
logdetail("Login successful, now calculating proof packet...");
|
||||
|
||||
// now lets start calculating
|
||||
BigNumber N,A,B,a,u,x,v,S,salt,unk1,g,k(3); // init BNs, default k to 3
|
||||
std::string user=stringToUpper( GetInstance()->GetConf()->accname );
|
||||
std::string _authstr=stringToUpper( user +":"+GetInstance()->GetConf()->accpass );
|
||||
|
||||
B.SetBinary(lc.B,32);
|
||||
g.SetBinary(lc.g,lc.g_len);
|
||||
N.SetBinary(lc.N,lc.N_len);
|
||||
salt.SetBinary(lc.salt,32);
|
||||
unk1.SetBinary(lc.unk3,16);
|
||||
|
||||
logdebug("== Server Bignums ==");
|
||||
logdebug("--> B=%s",B.AsHexStr());
|
||||
logdebug("--> g=%s",g.AsHexStr());
|
||||
logdebug("--> N=%s",N.AsHexStr());
|
||||
logdebug("--> salt=%s",salt.AsHexStr());
|
||||
logdebug("--> unk=%s",unk1.AsHexStr());
|
||||
|
||||
logdebug("== My Bignums ==");
|
||||
a.SetRand(19*8);
|
||||
ASSERT(a.AsDword() > 0);
|
||||
logdebug("--> a=%s",a.AsHexStr());
|
||||
Sha1Hash userhash,xhash,uhash;
|
||||
userhash.UpdateData(_authstr);
|
||||
userhash.Finalize();
|
||||
xhash.UpdateData(salt.AsByteArray(),salt.GetNumBytes());
|
||||
xhash.UpdateData(userhash.GetDigest(),userhash.GetLength());
|
||||
xhash.Finalize();
|
||||
x.SetBinary(xhash.GetDigest(),xhash.GetLength());
|
||||
logdebug("--> x=%s",x.AsHexStr());
|
||||
v=g.ModExp(x,N);
|
||||
logdebug("--> v=%s",v.AsHexStr());
|
||||
A=g.ModExp(a,N);
|
||||
logdebug("--> A=%s",A.AsHexStr());
|
||||
uhash.UpdateBigNumbers(&A, &B, NULL);
|
||||
uhash.Finalize();
|
||||
u.SetBinary(uhash.GetDigest(), 20);
|
||||
logdebug("--> u=%s",u.AsHexStr());
|
||||
S=(B - k*g.ModExp(x,N) ).ModExp((a + u * x),N);
|
||||
logdebug("--> S=%s",S.AsHexStr());
|
||||
ASSERT(S.AsDword() > 0);
|
||||
|
||||
|
||||
// calc M1 & M2
|
||||
unsigned int i=0;
|
||||
char S1[16+1],S2[16+1]; // 32/2=16 :) +1 for \0
|
||||
// split it into 2 seperate strings, interleaved
|
||||
for(i=0;i<16;i++){
|
||||
S1[i]=S.AsByteArray()[i*2];
|
||||
S2[i]=S.AsByteArray()[i*2+1];
|
||||
}
|
||||
|
||||
// hash each one:
|
||||
Sha1Hash S1hash,S2hash;
|
||||
S1hash.UpdateData((const uint8*)S1,16);
|
||||
S1hash.Finalize();
|
||||
S2hash.UpdateData((const uint8*)S2,16);
|
||||
S2hash.Finalize();
|
||||
// Re-combine them
|
||||
char S_hash[40];
|
||||
for(i=0;i<20;i++){
|
||||
S_hash[i*2]=S1hash.GetDigest()[i];
|
||||
S_hash[i*2+1]=S2hash.GetDigest()[i];
|
||||
}
|
||||
_key.SetBinary((uint8*)S_hash,40); // used later when authing to world
|
||||
logdebug("--> SessionKey=%s",_key.AsHexStr());
|
||||
|
||||
char Ng_hash[20];
|
||||
Sha1Hash userhash2,Nhash,ghash;
|
||||
userhash2.UpdateData((const uint8*)user.c_str(),user.length());
|
||||
userhash2.Finalize();
|
||||
//printchex((char*)userhash2.GetDigest(),userhash2.GetLength(),true);
|
||||
Nhash.UpdateBigNumbers(&N,NULL);
|
||||
Nhash.Finalize();
|
||||
ghash.UpdateBigNumbers(&g,NULL);
|
||||
ghash.Finalize();
|
||||
for(i=0;i<20;i++)Ng_hash[i] = Nhash.GetDigest()[i]^ghash.GetDigest()[i];
|
||||
//printchex(Ng_hash,20,true);
|
||||
|
||||
BigNumber t_acc,t_Ng_hash;
|
||||
t_acc.SetBinary((const uint8*)userhash2.GetDigest(),userhash2.GetLength());
|
||||
t_Ng_hash.SetBinary((const uint8*)Ng_hash,20);
|
||||
|
||||
|
||||
Sha1Hash M1hash,M2hash;
|
||||
|
||||
M1hash.UpdateBigNumbers(&t_Ng_hash,&t_acc,&salt,&A,&B,NULL);
|
||||
M1hash.UpdateData((const uint8*)S_hash,40);
|
||||
M1hash.Finalize();
|
||||
|
||||
M2hash.UpdateBigNumbers(&A,NULL);
|
||||
M2hash.UpdateData((const uint8*)M1hash.GetDigest(),M1hash.GetLength());
|
||||
M2hash.UpdateData((const uint8*)S_hash,40);
|
||||
M2hash.Finalize();
|
||||
|
||||
logdebug("== Common Hashes ==");
|
||||
logdebug("--> M1=%s",toHexDump(M1hash.GetDigest(),M1hash.GetLength(),false).c_str());
|
||||
logdebug("--> M2=%s",toHexDump(M2hash.GetDigest(),M2hash.GetLength(),false).c_str());
|
||||
|
||||
// Calc CRC & CRC_hash
|
||||
// i don't know yet how to calc it, so set it to zero
|
||||
char crc_hash[20];
|
||||
memset(crc_hash,0,20);
|
||||
|
||||
logdebug("--> CRC=%s",toHexDump((uint8*)crc_hash,20,false).c_str());
|
||||
|
||||
|
||||
// now lets prepare the packet
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)AUTH_LOGON_PROOF;
|
||||
packet.append(A.AsByteArray(),A.GetNumBytes());
|
||||
packet.append(M1hash.GetDigest(),M1hash.GetLength());
|
||||
packet.append(crc_hash,20);
|
||||
packet << (uint8)0; // number of keys = 0
|
||||
|
||||
if(GetInstance()->GetConf()->clientbuild > 5302)
|
||||
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
|
||||
|
||||
GetInstance()->SetSessionKey(_key);
|
||||
memcpy(this->_m2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later
|
||||
|
||||
SendRealmPacket(packet);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("Unknown realm server response! opcode=0x%x\n",(unsigned char)lc.error);
|
||||
DumpInvalidPacket(pkt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
|
||||
{
|
||||
logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]\n",pkt.size(),26);
|
||||
if(pkt.size() < 26)
|
||||
{
|
||||
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
|
||||
DumpInvalidPacket(pkt);
|
||||
if(GetInstance()->GetConf()->reconnect)
|
||||
SetMustDie();
|
||||
return;
|
||||
}
|
||||
sAuthLogonProof_S lp;
|
||||
pkt.read((uint8*)&lp, 26); // the compiler didnt like 'sizeof(sAuthLogonProof_S)', said it was 28
|
||||
//printchex((char*)&lp, sizeof(sAuthLogonProof_S),true);
|
||||
if(!memcmp(lp.M2,this->_m2,20))
|
||||
{
|
||||
// auth successful
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)REALM_LIST;
|
||||
packet << (uint32)0;
|
||||
SendRealmPacket(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
logcritical("Auth failed, M2 differs!");
|
||||
printf("My M2 :"); printchex((char*)_m2,20,true);
|
||||
printf("Srv M2:"); printchex((char*)lp.M2,20,true);
|
||||
|
||||
if(GetInstance()->GetConf()->reconnect)
|
||||
SetMustDie();
|
||||
else
|
||||
GetInstance()->SetError();
|
||||
}
|
||||
}
|
||||
|
||||
void RealmSession::DumpInvalidPacket(ByteBuffer& pkt)
|
||||
{
|
||||
if(pkt.size())
|
||||
logerror( toHexDump((uint8*)pkt.contents(),pkt.size()).c_str() );
|
||||
}
|
||||
|
||||
void RealmSession::SendRealmPacket(ByteBuffer& pkt)
|
||||
{
|
||||
if(_socket && _socket->IsOk())
|
||||
{
|
||||
if(pkt.size()) // dont send packets with no data
|
||||
_socket->SendBuf((const char*)pkt.contents(),pkt.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("Can't send realm packet, socket does not exist or is not ready!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
45
src/Client/Realm/RealmSession.h
Normal file
45
src/Client/Realm/RealmSession.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef REALMSESSION_H
|
||||
#define REALMSESSION_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct AuthHandler;
|
||||
class RealmSocket;
|
||||
|
||||
class RealmSession
|
||||
{
|
||||
public:
|
||||
RealmSession(PseuInstance*);
|
||||
~RealmSession();
|
||||
void AddToPktQueue(ByteBuffer*);
|
||||
void Connect(void);
|
||||
void Update(void);
|
||||
PseuInstance *GetInstance(void);
|
||||
void ClearSocket(void);
|
||||
void SendLogonChallenge(void);
|
||||
bool MustDie(void);
|
||||
void SetMustDie(void);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void _HandleRealmList(ByteBuffer&);
|
||||
void _HandleLogonProof(ByteBuffer&);
|
||||
void _HandleLogonChallenge(ByteBuffer&);
|
||||
AuthHandler *_GetAuthHandlerTable(void) const;
|
||||
void SendRealmPacket(ByteBuffer&);
|
||||
void DumpInvalidPacket(ByteBuffer&);
|
||||
|
||||
SocketHandler _sh;
|
||||
PseuInstance *_instance;
|
||||
ZThread::LockedQueue<ByteBuffer*,ZThread::FastMutex> pktQueue;
|
||||
RealmSocket *_socket;
|
||||
uint8 _m2[20];
|
||||
RealmSession *_session;
|
||||
BigNumber _key;
|
||||
bool _mustdie;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,473 +1,82 @@
|
||||
#include "common.h"
|
||||
#include "PseuWoW.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Auth/Sha1.h"
|
||||
#include "Auth/BigNumber.h"
|
||||
#include "RealmSession.h"
|
||||
#include "RealmSocket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
|
||||
|
||||
enum AuthCmd
|
||||
{
|
||||
AUTH_LOGON_CHALLENGE = 0x00,
|
||||
AUTH_LOGON_PROOF = 0x01,
|
||||
REALM_LIST = 0x10,
|
||||
};
|
||||
|
||||
struct SRealmHeader
|
||||
{
|
||||
uint8 cmd; // OP code = CMD_REALM_LIST
|
||||
uint16 size; // size of the rest of packet, without this part
|
||||
uint32 unknown; // 0x00 00 00 00
|
||||
uint8 count; // quantity of realms
|
||||
};
|
||||
|
||||
struct SRealmInfo
|
||||
{
|
||||
uint8 icon; // icon near realm
|
||||
uint8 locked; // added in 2.0.x
|
||||
uint8 color; // color of record
|
||||
std::string name; // Text zero terminated name of Realm
|
||||
std::string addr_port; // Text zero terminated address of Realm ("ip:port")
|
||||
float population; // 1.6 -> population value. lower == lower population and vice versa
|
||||
uint8 chars_here; // number of characters on this server
|
||||
uint8 timezone; // timezone
|
||||
uint8 unknown; //
|
||||
};
|
||||
|
||||
struct AuthHandler
|
||||
{
|
||||
uint32 cmd;
|
||||
void (RealmSocket::*handler)(void);
|
||||
};
|
||||
|
||||
struct sAuthLogonChallenge_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 unk2;
|
||||
uint8 B[32];
|
||||
uint8 g_len;
|
||||
uint8 g[1];
|
||||
uint8 N_len;
|
||||
uint8 N[32];
|
||||
uint8 salt[32];
|
||||
uint8 unk3[16];
|
||||
};
|
||||
|
||||
struct sAuthLogonProof_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
uint32 unk2;
|
||||
};
|
||||
|
||||
const AuthHandler table[]=
|
||||
{
|
||||
{AUTH_LOGON_CHALLENGE,&RealmSocket::_HandleLogonChallenge},
|
||||
{AUTH_LOGON_PROOF,&RealmSocket::_HandleLogonProof},
|
||||
{REALM_LIST,&RealmSocket::_HandleRealmList},
|
||||
{0,NULL}
|
||||
};
|
||||
|
||||
RealmSocket::RealmSocket(SocketHandler& h) : TcpSocket(h)
|
||||
{
|
||||
_instance=NULL;
|
||||
_valid=false;
|
||||
_rport=3724;
|
||||
_session = NULL;
|
||||
_ok = false;
|
||||
}
|
||||
|
||||
RealmSocket::~RealmSocket()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool RealmSocket::IsValid(void)
|
||||
{
|
||||
return _valid;
|
||||
}
|
||||
|
||||
void RealmSocket::SetHost(std::string h)
|
||||
{
|
||||
_rhost=h;
|
||||
}
|
||||
|
||||
void RealmSocket::SetPort(uint16 p)
|
||||
{
|
||||
_rport=p;
|
||||
}
|
||||
|
||||
void RealmSocket::SetInstance(PseuInstance *pi)
|
||||
{
|
||||
_instance=pi;
|
||||
}
|
||||
|
||||
void RealmSocket::Start(void)
|
||||
{
|
||||
if(_rhost.empty() || _rport==0 || _instance==NULL)
|
||||
return;
|
||||
log("Connecting to Realm Server on '%s:%u'",_rhost.c_str(),_rport);
|
||||
Open(_rhost,_rport);
|
||||
|
||||
//...
|
||||
_valid=true;
|
||||
}
|
||||
|
||||
void RealmSocket::Stop(void)
|
||||
{
|
||||
_valid=false;
|
||||
this->Close();
|
||||
memset(_m2,0,20);
|
||||
_key=0;
|
||||
}
|
||||
|
||||
void RealmSocket::_HandleRealmList(void)
|
||||
bool RealmSocket::IsOk(void)
|
||||
{
|
||||
std::string realmAddr;
|
||||
ByteBuffer realmbuf;
|
||||
realmbuf.resize(ibuf.GetLength());
|
||||
ibuf.Read((char*)realmbuf.contents(), ibuf.GetLength());
|
||||
return _ok;
|
||||
}
|
||||
|
||||
uint32 unk;
|
||||
uint16 len,count;
|
||||
uint8 cmd;
|
||||
realmbuf >> cmd >> len >> unk >> count;
|
||||
|
||||
// no realm?
|
||||
if(count==0)
|
||||
return;
|
||||
void RealmSocket::SetSession(RealmSession *rs)
|
||||
{
|
||||
_session = rs;
|
||||
}
|
||||
|
||||
// alloc space for as many realms as needed
|
||||
SRealmInfo *realms=new SRealmInfo[count];
|
||||
|
||||
// readout realms
|
||||
for(uint8 i=0;i<count;i++)
|
||||
{
|
||||
realmbuf >> realms[i].icon;
|
||||
realmbuf >> realms[i].locked;
|
||||
realmbuf >> realms[i].color;
|
||||
realmbuf >> realms[i].name;
|
||||
realmbuf >> realms[i].addr_port;
|
||||
realmbuf >> realms[i].population;
|
||||
realmbuf >> realms[i].chars_here;
|
||||
realmbuf >> realms[i].timezone;
|
||||
realmbuf >> realms[i].unknown;
|
||||
}
|
||||
|
||||
// the rest of the packet is not interesting
|
||||
|
||||
for(uint8 i=0;i<count;i++)
|
||||
{
|
||||
if(realms[i].name==GetInstance()->GetConf()->realmname)
|
||||
{
|
||||
realmAddr=realms[i].addr_port;
|
||||
}
|
||||
logcustom(0,LGREEN,"Realm: %s (%s)",realms[i].name.c_str(),realms[i].addr_port.c_str());
|
||||
logdetail(" [chars:%d][population:%f][timezone:%d]",realms[i].chars_here,realms[i].population,realms[i].timezone);
|
||||
}
|
||||
delete [] realms;
|
||||
|
||||
// now setup where the woldserver is and how to login there
|
||||
if(realmAddr.empty()){
|
||||
log("Realm \"%s\" was not found on the realmlist!",GetInstance()->GetConf()->realmname.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// transform "hostname:port" into something useful
|
||||
// -> convert the worldserver port from string to int
|
||||
// -> write it into the config & set appropriate vars
|
||||
|
||||
uint16 colonpos=realmAddr.find(":");
|
||||
GetInstance()->GetConf()->worldhost=realmAddr.substr(0,colonpos);
|
||||
GetInstance()->GetConf()->worldport=atoi(realmAddr.substr(colonpos+1,realmAddr.length()-colonpos-1).c_str());
|
||||
// set vars
|
||||
GetInstance()->GetScripts()->variables.Set("WORLDHOST",GetInstance()->GetConf()->worldhost);
|
||||
GetInstance()->GetScripts()->variables.Set("WORLDPORT",toString((uint64)(GetInstance()->GetConf()->worldport)));
|
||||
|
||||
// now we have the correct addr/port, time to create the WorldSession
|
||||
GetInstance()->createWorldSession=true;
|
||||
int RealmSocket::Close(void)
|
||||
{
|
||||
_ok = false;
|
||||
return TcpSocket::Close();
|
||||
}
|
||||
|
||||
|
||||
void RealmSocket::OnRead(void)
|
||||
{
|
||||
TcpSocket::OnRead();
|
||||
bool known=false;
|
||||
//printf("RealmSocket::OnRead() %u bytes\n",ibuf.GetLength());
|
||||
if(!ibuf.GetLength())
|
||||
uint32 len = ibuf.GetLength();
|
||||
logdev("RealmSocket::OnRead() %u bytes",len);
|
||||
if(!len)
|
||||
return;
|
||||
uint8 cmd, i=0;
|
||||
ibuf.SoftRead((char*)&cmd, 1);
|
||||
for(uint8 i=0;table[i].handler!=NULL;i++)
|
||||
{
|
||||
if(table[i].cmd==cmd)
|
||||
{
|
||||
(*this.*table[i].handler)();
|
||||
known=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!known)
|
||||
{
|
||||
log("RealmSocket: Got unknown packet, cmd=%u",cmd);
|
||||
}
|
||||
if(ibuf.GetLength())
|
||||
{
|
||||
uint32 len = ibuf.GetLength();
|
||||
char *data = new char[len];
|
||||
ibuf.Read(data,len); // if we have data crap left on the buf, delete it
|
||||
logdebug("Data left on RealmSocket, Hexdump:");
|
||||
logdebug(toHexDump((uint8*)data,len).c_str());
|
||||
delete [] data;
|
||||
}
|
||||
ByteBuffer *pkt = new ByteBuffer(len);
|
||||
uint8* data = new uint8[len];
|
||||
ibuf.Read((char*)data,len);
|
||||
pkt->append(data,len);
|
||||
delete [] data;
|
||||
_session->AddToPktQueue(pkt);
|
||||
}
|
||||
|
||||
|
||||
void RealmSocket::SendLogonChallenge(void)
|
||||
RealmSession *RealmSocket::GetSession(void)
|
||||
{
|
||||
if(!this->Ready())
|
||||
{
|
||||
logerror("Error sending AUTH_LOGON_CHALLENGE, port is not ready!\n");
|
||||
return;
|
||||
}
|
||||
if( GetInstance()->GetConf()->accname.empty() || GetInstance()->GetConf()->clientversion_string.empty()
|
||||
|| GetInstance()->GetConf()->clientbuild==0 || GetInstance()->GetConf()->clientlang.empty() )
|
||||
{
|
||||
logcritical("Missing data, can't send Login to Realm Server!");
|
||||
GetInstance()->SetError();
|
||||
return;
|
||||
}
|
||||
std::string acc = stringToUpper(GetInstance()->GetConf()->accname);
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)AUTH_LOGON_CHALLENGE;
|
||||
packet << (uint8)2;
|
||||
packet << (uint8)(acc.length()+30); // length of the rest of the packet
|
||||
packet << (uint8)0;
|
||||
packet.append("WOW",3); // game name = World Of Warcraft
|
||||
packet.append(GetInstance()->GetConf()->clientversion,3); // 1.12.2 etc
|
||||
packet << (uint8)0;
|
||||
packet << (uint16)(GetInstance()->GetConf()->clientbuild); // (uint16) 5875
|
||||
packet << "68x" << "niW"; // "x86" - platform; "Win" - Operating system; both reversed and zero terminated
|
||||
for(uint8 i=0;i<4;i++)
|
||||
packet << (uint8)(GetInstance()->GetConf()->clientlang[3-i]); // "enUS" -> "SUne" : reversed and NOT zero terminated
|
||||
packet << (uint32)0x3c; // timezone
|
||||
packet << (uint32)GetClientRemoteAddr(); // my IP address
|
||||
packet << (uint8)acc.length(); // length of acc name without \0
|
||||
packet.append(acc.c_str(),acc.length()); // append accname, skip \0
|
||||
|
||||
SendBuf((char*)packet.contents(),packet.size());
|
||||
|
||||
return _session;
|
||||
}
|
||||
|
||||
PseuInstance *RealmSocket::GetInstance(void)
|
||||
void RealmSocket::OnAccept(void)
|
||||
{
|
||||
return _instance;
|
||||
logdev("RealmSocket accepted.");
|
||||
}
|
||||
|
||||
void RealmSocket::_HandleLogonChallenge(void)
|
||||
{
|
||||
logdebug("RealmSocket: Got AUTH_LOGON_CHALLENGE [%u of %u bytes]",ibuf.GetLength(),sizeof(sAuthLogonChallenge_S));
|
||||
if(ibuf.GetLength() < sizeof(sAuthLogonChallenge_S))
|
||||
{
|
||||
logerror("AUTH_LOGON_CHALLENGE: Recieved incorrect/unknown packet. Hexdump:");
|
||||
uint32 len = ibuf.GetLength();
|
||||
char* data = new char[len];
|
||||
ibuf.Read(data,len);
|
||||
logerror(toHexDump((uint8*)data,len).c_str());
|
||||
delete [] data;
|
||||
return;
|
||||
}
|
||||
|
||||
sAuthLogonChallenge_S lc;
|
||||
ibuf.Read((char*)&lc, sizeof(sAuthLogonChallenge_S));
|
||||
|
||||
switch (lc.error)
|
||||
{
|
||||
case 4:
|
||||
log("Realm Server did not find account \"%s\"!",GetInstance()->GetConf()->accname.c_str());
|
||||
break;
|
||||
case 6:
|
||||
log("Account \"%s\" is already logged in!",GetInstance()->GetConf()->accname.c_str());
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
logdetail("Login successful, now calculating proof packet...");
|
||||
|
||||
// now lets start calculating
|
||||
BigNumber N,A,B,a,u,x,v,S,salt,unk1,g,k(3); // init BNs, default k to 3
|
||||
std::string user=stringToUpper( GetInstance()->GetConf()->accname );
|
||||
std::string _authstr=stringToUpper( user +":"+GetInstance()->GetConf()->accpass );
|
||||
|
||||
B.SetBinary(lc.B,32);
|
||||
g.SetBinary(lc.g,lc.g_len);
|
||||
N.SetBinary(lc.N,lc.N_len);
|
||||
salt.SetBinary(lc.salt,32);
|
||||
unk1.SetBinary(lc.unk3,16);
|
||||
|
||||
logdebug("== Server Bignums ==");
|
||||
logdebug("--> B=%s",B.AsHexStr());
|
||||
logdebug("--> g=%s",g.AsHexStr());
|
||||
logdebug("--> N=%s",N.AsHexStr());
|
||||
logdebug("--> salt=%s",salt.AsHexStr());
|
||||
logdebug("--> unk=%s",unk1.AsHexStr());
|
||||
|
||||
logdebug("== My Bignums ==");
|
||||
a.SetRand(19*8);
|
||||
ASSERT(a.AsDword() > 0);
|
||||
logdebug("--> a=%s",a.AsHexStr());
|
||||
Sha1Hash userhash,xhash,uhash;
|
||||
userhash.UpdateData(_authstr);
|
||||
userhash.Finalize();
|
||||
xhash.UpdateData(salt.AsByteArray(),salt.GetNumBytes());
|
||||
xhash.UpdateData(userhash.GetDigest(),userhash.GetLength());
|
||||
xhash.Finalize();
|
||||
x.SetBinary(xhash.GetDigest(),xhash.GetLength());
|
||||
logdebug("--> x=%s",x.AsHexStr());
|
||||
v=g.ModExp(x,N);
|
||||
logdebug("--> v=%s",v.AsHexStr());
|
||||
A=g.ModExp(a,N);
|
||||
logdebug("--> A=%s",A.AsHexStr());
|
||||
uhash.UpdateBigNumbers(&A, &B, NULL);
|
||||
uhash.Finalize();
|
||||
u.SetBinary(uhash.GetDigest(), 20);
|
||||
logdebug("--> u=%s",u.AsHexStr());
|
||||
S=(B - k*g.ModExp(x,N) ).ModExp((a + u * x),N);
|
||||
logdebug("--> S=%s",S.AsHexStr());
|
||||
ASSERT(S.AsDword() > 0);
|
||||
|
||||
|
||||
// calc M1 & M2
|
||||
unsigned int i=0;
|
||||
char S1[16+1],S2[16+1]; // 32/2=16 :) +1 for \0
|
||||
// split it into 2 seperate strings, interleaved
|
||||
for(i=0;i<16;i++){
|
||||
S1[i]=S.AsByteArray()[i*2];
|
||||
S2[i]=S.AsByteArray()[i*2+1];
|
||||
}
|
||||
|
||||
// hash each one:
|
||||
Sha1Hash S1hash,S2hash;
|
||||
S1hash.UpdateData((const uint8*)S1,16);
|
||||
S1hash.Finalize();
|
||||
S2hash.UpdateData((const uint8*)S2,16);
|
||||
S2hash.Finalize();
|
||||
// Re-combine them
|
||||
char S_hash[40];
|
||||
for(i=0;i<20;i++){
|
||||
S_hash[i*2]=S1hash.GetDigest()[i];
|
||||
S_hash[i*2+1]=S2hash.GetDigest()[i];
|
||||
}
|
||||
_key.SetBinary((uint8*)S_hash,40); // used later when authing to world
|
||||
logdebug("--> SessionKey=%s",_key.AsHexStr());
|
||||
|
||||
char Ng_hash[20];
|
||||
Sha1Hash userhash2,Nhash,ghash;
|
||||
userhash2.UpdateData((const uint8*)user.c_str(),user.length());
|
||||
userhash2.Finalize();
|
||||
//printchex((char*)userhash2.GetDigest(),userhash2.GetLength(),true);
|
||||
Nhash.UpdateBigNumbers(&N,NULL);
|
||||
Nhash.Finalize();
|
||||
ghash.UpdateBigNumbers(&g,NULL);
|
||||
ghash.Finalize();
|
||||
for(i=0;i<20;i++)Ng_hash[i] = Nhash.GetDigest()[i]^ghash.GetDigest()[i];
|
||||
//printchex(Ng_hash,20,true);
|
||||
|
||||
BigNumber t_acc,t_Ng_hash;
|
||||
t_acc.SetBinary((const uint8*)userhash2.GetDigest(),userhash2.GetLength());
|
||||
t_Ng_hash.SetBinary((const uint8*)Ng_hash,20);
|
||||
|
||||
|
||||
Sha1Hash M1hash,M2hash;
|
||||
|
||||
M1hash.UpdateBigNumbers(&t_Ng_hash,&t_acc,&salt,&A,&B,NULL);
|
||||
M1hash.UpdateData((const uint8*)S_hash,40);
|
||||
M1hash.Finalize();
|
||||
|
||||
M2hash.UpdateBigNumbers(&A,NULL);
|
||||
M2hash.UpdateData((const uint8*)M1hash.GetDigest(),M1hash.GetLength());
|
||||
M2hash.UpdateData((const uint8*)S_hash,40);
|
||||
M2hash.Finalize();
|
||||
|
||||
logdebug("== Common Hashes ==");
|
||||
logdebug("--> M1=%s",toHexDump(M1hash.GetDigest(),M1hash.GetLength(),false).c_str());
|
||||
logdebug("--> M2=%s",toHexDump(M2hash.GetDigest(),M2hash.GetLength(),false).c_str());
|
||||
|
||||
// Calc CRC & CRC_hash
|
||||
// i don't know yet how to calc it, so set it to zero
|
||||
char crc_hash[20];
|
||||
memset(crc_hash,0,20);
|
||||
|
||||
logdebug("--> CRC=%s",toHexDump((uint8*)crc_hash,20,false).c_str());
|
||||
|
||||
|
||||
// now lets prepare the packet
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)AUTH_LOGON_PROOF;
|
||||
packet.append(A.AsByteArray(),A.GetNumBytes());
|
||||
packet.append(M1hash.GetDigest(),M1hash.GetLength());
|
||||
packet.append(crc_hash,20);
|
||||
packet << (uint8)0; // number of keys = 0
|
||||
|
||||
if(GetInstance()->GetConf()->clientbuild > 5302)
|
||||
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
|
||||
|
||||
GetInstance()->SetSessionKey(_key);
|
||||
memcpy(this->_m2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later
|
||||
|
||||
SendBuf((char*)packet.contents(),packet.size());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("Unknown realm server response! opcode=0x%x\n",(unsigned char)lc.error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RealmSocket::_HandleLogonProof(void)
|
||||
{
|
||||
logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]\n",ibuf.GetLength(),26);
|
||||
if(ibuf.GetLength() < 26)
|
||||
{
|
||||
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
|
||||
uint32 len = ibuf.GetLength();
|
||||
char* data = new char[len];
|
||||
ibuf.Read(data,len);
|
||||
logerror(toHexDump((uint8*)data,len).c_str());
|
||||
delete [] data;
|
||||
return;
|
||||
}
|
||||
sAuthLogonProof_S lp;
|
||||
ibuf.Read((char*)&lp, 26); // the compiler didnt like 'sizeof(sAuthLogonProof_S)', said it was 28
|
||||
//printchex((char*)&lp, sizeof(sAuthLogonProof_S),true);
|
||||
if(!memcmp(lp.M2,this->_m2,20))
|
||||
{
|
||||
// auth successful
|
||||
ByteBuffer packet;
|
||||
packet << (uint8)REALM_LIST;
|
||||
packet << (uint32)0;
|
||||
SendBuf((char*)packet.contents(),packet.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
logcritical("Auth failed, M2 differs!");
|
||||
printf("My M2 :"); printchex((char*)_m2,20,true);
|
||||
printf("Srv M2:"); printchex((char*)lp.M2,20,true);
|
||||
GetInstance()->SetError();
|
||||
}
|
||||
}
|
||||
|
||||
void RealmSocket::OnConnect()
|
||||
void RealmSocket::OnConnect(void)
|
||||
{
|
||||
logdetail("RealmSocket connected!");
|
||||
SendLogonChallenge();
|
||||
_ok = true;
|
||||
}
|
||||
|
||||
void RealmSocket::OnConnectFailed(void)
|
||||
{
|
||||
logerror("Connecting to Realm failed!");
|
||||
_ok = false;
|
||||
}
|
||||
|
||||
void RealmSocket::OnException(void)
|
||||
{
|
||||
logerror("RealmSocket: Exception!");
|
||||
_ok = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,52 +1,34 @@
|
||||
|
||||
|
||||
|
||||
#ifndef _REALMSOCKET_H
|
||||
#define _REALMSOCKET_H
|
||||
|
||||
#include "Network/ResolvSocket.h"
|
||||
#include "PseuWoW.h"
|
||||
#include "Network/TcpSocket.h"
|
||||
|
||||
class RealmSession;
|
||||
|
||||
class RealmSocket : public TcpSocket
|
||||
{
|
||||
public:
|
||||
RealmSocket(SocketHandler &h);
|
||||
~RealmSocket();
|
||||
PseuInstance *GetInstance(void);
|
||||
bool IsValid(void);
|
||||
void SetInstance(PseuInstance*);
|
||||
|
||||
void SetHost(std::string);
|
||||
void SetPort(uint16);
|
||||
RealmSession *GetSession(void);
|
||||
bool IsOk(void);
|
||||
void SetSession(RealmSession*);
|
||||
|
||||
|
||||
|
||||
void Start(void);
|
||||
void Stop(void);
|
||||
void Update(void);
|
||||
void SendLogonChallenge(void);
|
||||
|
||||
// dont use from outside!!
|
||||
void _HandleRealmList(void);
|
||||
void _HandleLogonProof(void);
|
||||
void _HandleLogonChallenge(void);
|
||||
|
||||
void OnRead(void);
|
||||
void OnConnect(void);
|
||||
void OnConnectFailed(void);
|
||||
void OnException(void);
|
||||
void OnAccept(void);
|
||||
int Close(void);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
uint16 _rport;
|
||||
std::string _rhost;
|
||||
uint8 _m2[20];
|
||||
PseuInstance *_instance;
|
||||
BigNumber _key;
|
||||
bool _valid;
|
||||
ByteBuffer _data;
|
||||
bool _ok;
|
||||
RealmSession *_session;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include "Channel.h"
|
||||
|
||||
void WorldSession::SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to){
|
||||
if((!_valid) || (!_logged) || msg.empty())
|
||||
if((!_logged) || msg.empty())
|
||||
return;
|
||||
WorldPacket packet;
|
||||
packet<<type<<lang;
|
||||
|
||||
@ -8,21 +8,26 @@
|
||||
#include "WorldSocket.h"
|
||||
#include "RealmSocket.h"
|
||||
#include "Channel.h"
|
||||
|
||||
#include "RealmSession.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
struct OpcodeHandler
|
||||
{
|
||||
uint16 opcode;
|
||||
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
||||
};
|
||||
|
||||
|
||||
WorldSession::WorldSession(PseuInstance *in)
|
||||
{
|
||||
logdebug("-> Starting WorldSession from instance 0x%X",in); // should never output a null ptr
|
||||
_instance = in;
|
||||
_valid=_authed=_logged=false;
|
||||
_socket=new WorldSocket(_sh,this);
|
||||
_mustdie=false;
|
||||
_logged=false;
|
||||
_socket=NULL;
|
||||
_myGUID=0; // i dont have a guid yet
|
||||
plrNameCache.ReadFromFile(); // load names/guids of known players
|
||||
ItemProtoCache_InsertDataToSession(this);
|
||||
_deleteme = false;
|
||||
_channels = new Channel(this);
|
||||
_sh.SetAutoCloseSockets(false);
|
||||
//...
|
||||
}
|
||||
|
||||
@ -30,40 +35,43 @@ WorldSession::~WorldSession()
|
||||
{
|
||||
WorldPacket *packet;
|
||||
// clear the queue
|
||||
while(!pktQueue.empty())
|
||||
while(pktQueue.size())
|
||||
{
|
||||
packet = pktQueue.next();
|
||||
delete packet;
|
||||
}
|
||||
_OnLeaveWorld();
|
||||
|
||||
delete _channels;
|
||||
//delete _socket; the socket will be deleted by its handler!!
|
||||
if(_channels)
|
||||
delete _channels;
|
||||
if(_socket)
|
||||
delete _socket;
|
||||
}
|
||||
|
||||
void WorldSession::Start(void)
|
||||
{
|
||||
log("Connecting to '%s' on port %u",GetInstance()->GetConf()->worldhost.c_str(),GetInstance()->GetConf()->worldport);
|
||||
_socket=new WorldSocket(_sh,this);
|
||||
_socket->Open(GetInstance()->GetConf()->worldhost,GetInstance()->GetConf()->worldport);
|
||||
if(GetInstance()->GetRSession())
|
||||
{
|
||||
GetInstance()->GetRSession()->SetCloseAndDelete(); // realm socket is no longer needed
|
||||
GetInstance()->deleterealm=true;
|
||||
GetInstance()->GetRSession()->SetMustDie(); // realm session is no longer needed
|
||||
}
|
||||
_valid=true;
|
||||
_sh.Add(_socket);
|
||||
_socket->SetDeleteByHandler();
|
||||
_sh.Select(1,0);
|
||||
|
||||
// if we cant connect, wait until the socket gives up (after 5 secs)
|
||||
while( (!MustDie()) && (!_socket->IsOk()) && (!GetInstance()->Stopped()) )
|
||||
{
|
||||
_sh.Select(3,0);
|
||||
GetInstance()->Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
bool WorldSession::DeleteMe(void)
|
||||
void WorldSession::_LoadCache(void)
|
||||
{
|
||||
return _deleteme;
|
||||
}
|
||||
|
||||
void WorldSession::SetSocket(WorldSocket *sock)
|
||||
{
|
||||
_socket = sock;
|
||||
logdetail("Loading Cache...");
|
||||
plrNameCache.ReadFromFile(); // load names/guids of known players
|
||||
ItemProtoCache_InsertDataToSession(this);
|
||||
//...
|
||||
}
|
||||
|
||||
void WorldSession::AddToPktQueue(WorldPacket *pkt)
|
||||
@ -75,37 +83,25 @@ void WorldSession::SendWorldPacket(WorldPacket &pkt)
|
||||
{
|
||||
if(GetInstance()->GetConf()->showmyopcodes)
|
||||
logcustom(0,BROWN,"<< Opcode %u [%s]", pkt.GetOpcode(), GetOpcodeName(pkt.GetOpcode()));
|
||||
_socket->SendWorldPacket(pkt);
|
||||
if(_socket && _socket->IsOk())
|
||||
_socket->SendWorldPacket(pkt);
|
||||
else
|
||||
{
|
||||
logerror("WorldSession: Can't send WorldPacket, socket doesn't exist or is not ready.");
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::Update(void)
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
if( _socket && _sh.GetCount() )
|
||||
if( _sh.GetCount() ) // the socketwil remove itself from the handler if it got closed
|
||||
_sh.Select(0,0);
|
||||
|
||||
/*if(!_socket)
|
||||
{
|
||||
if(_valid)
|
||||
{
|
||||
_deleteme = true;
|
||||
}
|
||||
_logged=_authed=_valid=false;
|
||||
return;
|
||||
}*/
|
||||
|
||||
if(!_socket)
|
||||
{
|
||||
if(_valid)
|
||||
{
|
||||
this->Start();
|
||||
}
|
||||
_logged=_authed=_valid=false;
|
||||
return;
|
||||
else // so we just need to check if the socket doesnt exist or if it exists but isnt valid anymore.
|
||||
{ // if thats the case, we dont need the session anymore either
|
||||
if(!_socket || (_socket && !_socket->IsOk()))
|
||||
SetMustDie();
|
||||
}
|
||||
|
||||
|
||||
OpcodeHandler *table = _GetOpcodeHandlerTable();
|
||||
bool known=false;
|
||||
while(pktQueue.size())
|
||||
@ -212,7 +208,7 @@ void WorldSession::SetTarget(uint64 guid)
|
||||
|
||||
void WorldSession::_OnEnterWorld(void)
|
||||
{
|
||||
if(!_logged)
|
||||
if(!InWorld())
|
||||
{
|
||||
_logged=true;
|
||||
GetInstance()->GetScripts()->variables.Set("@inworld","true");
|
||||
@ -223,7 +219,7 @@ void WorldSession::_OnEnterWorld(void)
|
||||
|
||||
void WorldSession::_OnLeaveWorld(void)
|
||||
{
|
||||
if(_logged)
|
||||
if(InWorld())
|
||||
{
|
||||
_logged=false;
|
||||
GetInstance()->GetScripts()->RunScript("_leaveworld",NULL);
|
||||
@ -234,7 +230,7 @@ void WorldSession::_OnLeaveWorld(void)
|
||||
void WorldSession::_DoTimedActions(void)
|
||||
{
|
||||
static clock_t pingtime=0;
|
||||
if(_logged)
|
||||
if(InWorld())
|
||||
{
|
||||
if(pingtime < clock())
|
||||
{
|
||||
@ -283,8 +279,6 @@ void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket)
|
||||
// so its not 100% correct to init the crypt here, but it should do the job if authing was correct
|
||||
_socket->InitCrypt(GetInstance()->GetSessionKey().AsByteArray(), 40);
|
||||
|
||||
_authed=true;
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
|
||||
@ -314,6 +308,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
|
||||
GetInstance()->SetError();
|
||||
return;
|
||||
}
|
||||
_LoadCache(); // we are about to login, so we need cache data
|
||||
logdetail("W: Chars in list: %u\n",num);
|
||||
for(unsigned int i=0;i<num;i++){
|
||||
recvPacket >> plr[i]._guid;
|
||||
|
||||
@ -13,14 +13,8 @@
|
||||
class WorldSocket;
|
||||
class WorldPacket;
|
||||
class Channel;
|
||||
|
||||
|
||||
|
||||
struct OpcodeHandler
|
||||
{
|
||||
uint16 opcode;
|
||||
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
||||
};
|
||||
class RealmSession;
|
||||
struct OpcodeHandler;
|
||||
|
||||
|
||||
class WorldSession
|
||||
@ -33,17 +27,13 @@ public:
|
||||
PseuInstance *GetInstance(void) { return _instance; }
|
||||
SCPDatabaseMgr& GetDBMgr(void) { return GetInstance()->dbmgr; }
|
||||
|
||||
OpcodeHandler *_GetOpcodeHandlerTable(void) const;
|
||||
|
||||
void SetSocket(WorldSocket *sock);
|
||||
|
||||
void AddToPktQueue(WorldPacket *pkt);
|
||||
void Connect(std::string addr,uint16 port);
|
||||
void Update(void);
|
||||
void Start(void);
|
||||
bool IsValid(void) { return _valid; }
|
||||
bool DeleteMe(void);
|
||||
bool MustDie(void) { return _mustdie; }
|
||||
void SetMustDie(void) { _mustdie = true; }
|
||||
void SendWorldPacket(WorldPacket&);
|
||||
bool InWorld(void) { return _logged; }
|
||||
|
||||
void SetTarget(uint64 guid);
|
||||
uint64 GetTarget(void) { return GetMyChar()->GetTarget(); }
|
||||
@ -65,6 +55,7 @@ public:
|
||||
ObjMgr objmgr;
|
||||
|
||||
private:
|
||||
OpcodeHandler *_GetOpcodeHandlerTable(void) const;
|
||||
|
||||
// Helpers
|
||||
void _OnEnterWorld(void); // = login
|
||||
@ -99,10 +90,12 @@ private:
|
||||
void _ValuesUpdate(uint64 uguid, WorldPacket& recvPacket); // ...
|
||||
void _QueryObjectInfo(uint64 guid);
|
||||
|
||||
void _LoadCache(void);
|
||||
|
||||
PseuInstance *_instance;
|
||||
WorldSocket *_socket;
|
||||
ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> pktQueue;
|
||||
bool _valid,_authed,_logged,_deleteme; // world status
|
||||
bool _logged,_mustdie; // world status
|
||||
SocketHandler _sh; // handles the WorldSocket
|
||||
Channel *_channels;
|
||||
uint64 _myGUID;
|
||||
|
||||
@ -7,32 +7,40 @@ WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
|
||||
{
|
||||
_session = s;
|
||||
_gothdr = false;
|
||||
_ok=false;
|
||||
}
|
||||
|
||||
bool WorldSocket::IsOk(void)
|
||||
{
|
||||
return _ok;
|
||||
}
|
||||
|
||||
|
||||
void WorldSocket::OnConnect()
|
||||
{
|
||||
log("Connected to world server.\r\n");
|
||||
log("Connected to world server.");
|
||||
_ok = true;
|
||||
}
|
||||
|
||||
void WorldSocket::OnConnectFailed()
|
||||
{
|
||||
logerror("WorldSocket::OnConnectFailed()\n");
|
||||
if(_session)
|
||||
_session->SetSocket(NULL);
|
||||
logerror("Connecting to World Server failed!");
|
||||
_ok = false;
|
||||
}
|
||||
|
||||
void WorldSocket::OnDelete()
|
||||
{
|
||||
log("Connection to world server has been closed.\n");
|
||||
if(_session)
|
||||
_session->SetSocket(NULL);
|
||||
log("Connection to world server has been closed.");
|
||||
_ok = false;
|
||||
_session->SetMustDie(); // recreate the session if needed
|
||||
}
|
||||
|
||||
void WorldSocket::OnException()
|
||||
{
|
||||
DEBUG(logdebug("WorldSocket::OnException()"));
|
||||
this->SetCloseAndDelete();
|
||||
if(_ok)
|
||||
{
|
||||
logerror("WorldSocket::OnException()");
|
||||
_ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSocket::OnRead()
|
||||
@ -100,6 +108,8 @@ void WorldSocket::OnRead()
|
||||
|
||||
void WorldSocket::SendWorldPacket(WorldPacket &pkt)
|
||||
{
|
||||
if(!_ok)
|
||||
return;
|
||||
ClientPktHeader hdr;
|
||||
memset(&hdr,0,sizeof(ClientPktHeader));
|
||||
hdr.size = ntohs(pkt.size()+4);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef _WORLDSOCKET_H
|
||||
#define _WORLDSOCKET_H
|
||||
|
||||
#include "Network/ResolvSocket.h"
|
||||
#include "Network/TcpSocket.h"
|
||||
#include "SysDefs.h"
|
||||
|
||||
class WorldSession;
|
||||
@ -24,6 +24,7 @@ class WorldSocket : public TcpSocket
|
||||
public:
|
||||
WorldSocket(SocketHandler &h, WorldSession *s);
|
||||
WorldSession *GetSession(void) { return _session; }
|
||||
bool IsOk();
|
||||
|
||||
void OnRead();
|
||||
void OnConnect();
|
||||
@ -40,6 +41,7 @@ private:
|
||||
bool _gothdr; // true if only the header was recieved yet
|
||||
uint16 _opcode; // stores the last recieved opcode
|
||||
uint16 _remaining; // bytes amount of the next data packet
|
||||
bool _ok;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -383,6 +383,12 @@
|
||||
<Filter
|
||||
Name="Realm"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\Client\Realm\RealmSession.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client\Realm\RealmSession.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client\Realm\RealmSocket.cpp">
|
||||
</File>
|
||||
|
||||
@ -123,6 +123,9 @@
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
||||
<File
|
||||
RelativePath=".\shared\ByteBuffer.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\shared\common.h">
|
||||
</File>
|
||||
|
||||
@ -55,6 +55,7 @@ SocketHandler::SocketHandler(StdLog *p)
|
||||
,m_bTryDirect(false)
|
||||
,m_resolv_id(0)
|
||||
,m_resolver(NULL)
|
||||
,m_auto_close_sockets(true)
|
||||
{
|
||||
FD_ZERO(&m_rfds);
|
||||
FD_ZERO(&m_wfds);
|
||||
@ -68,16 +69,20 @@ SocketHandler::~SocketHandler()
|
||||
m_resolver -> Quit();
|
||||
if (!m_slave)
|
||||
{
|
||||
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
||||
if(m_auto_close_sockets)
|
||||
{
|
||||
Socket *p = (*it).second;
|
||||
p -> Close();
|
||||
// p -> OnDelete(); // hey, I turn this back on. what's the worst that could happen??!!
|
||||
// MinionSocket breaks, calling MinderHandler methods in OnDelete -
|
||||
// MinderHandler is already gone when that happens...
|
||||
if (p -> DeleteByHandler())
|
||||
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
||||
{
|
||||
delete p;
|
||||
Socket *p = (*it).second;
|
||||
if(p)
|
||||
{
|
||||
p -> Close();
|
||||
p -> OnDelete();
|
||||
if (p -> DeleteByHandler())
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,8 @@ class SocketHandler
|
||||
SocketHandler(StdLog * = NULL);
|
||||
virtual ~SocketHandler();
|
||||
|
||||
void SetAutoCloseSockets(bool x=true) { m_auto_close_sockets = x; }
|
||||
|
||||
/** Register StdLog object for error callback. */
|
||||
void RegStdLog(StdLog *);
|
||||
void LogError(Socket *,const std::string&,int,const std::string&,loglevel_t = LOG_LEVEL_WARNING);
|
||||
@ -119,5 +121,6 @@ class SocketHandler
|
||||
int m_resolv_id;
|
||||
ResolvServer *m_resolver;
|
||||
port_t m_resolver_port;
|
||||
bool m_auto_close_sockets;
|
||||
};
|
||||
#endif // _SOCKETHANDLER_H
|
||||
|
||||
@ -257,10 +257,9 @@ void ExtractMaps(void)
|
||||
fh.write((char*)bb.contents(),bb.size());
|
||||
fh.close();
|
||||
extr++;
|
||||
printf("Map [%u/%u]: %s: %u\r",it+1,mapNames.size(),mapNames[it].c_str(),extr);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Map [%u/%u]: %s: %u\r",it+1,mapNames.size(),mapNames[it].c_str(),extr);
|
||||
}
|
||||
}
|
||||
extrtotal+=extr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user