* 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
|
exitonerror=0
|
||||||
|
|
||||||
// reconnect on failure/disconnect
|
// 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
|
// 0 - show none
|
||||||
// 1 - show only known/handled
|
// 1 - show only known/handled
|
||||||
@ -33,13 +36,14 @@ showopcodes=3
|
|||||||
hidefreqopcodes=1
|
hidefreqopcodes=1
|
||||||
|
|
||||||
|
|
||||||
// the IP or hostname the wow server is running on
|
// the IP or hostname the realm server is running on
|
||||||
realmlist=localhost
|
realmlist=localhost
|
||||||
|
|
||||||
// port on which the realm server is listening (default=3724)
|
// port on which the realm server is listening (default=3724)
|
||||||
realmport=3724
|
realmport=3724
|
||||||
|
|
||||||
// PseuWoW will login on this realm
|
// PseuWoW will login on this realm
|
||||||
|
// Case sensitive!
|
||||||
realmname=My WoW Realm
|
realmname=My WoW Realm
|
||||||
|
|
||||||
// your account name
|
// your account name
|
||||||
@ -48,8 +52,9 @@ accname=test
|
|||||||
// your account password
|
// your account password
|
||||||
accpass=test
|
accpass=test
|
||||||
|
|
||||||
// the character name PseuWoW should choose to enter the world
|
// the character name PseuWoW should choose to enter the world.
|
||||||
charname=PseuWoW
|
// case sensitive!
|
||||||
|
charname=Pseuwow
|
||||||
|
|
||||||
|
|
||||||
// Client emulation configuration
|
// Client emulation configuration
|
||||||
@ -104,3 +109,4 @@ enablegui=0
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ name=Shaman
|
|||||||
name=Mage
|
name=Mage
|
||||||
|
|
||||||
[9]
|
[9]
|
||||||
name=Paladin
|
name=Warlock
|
||||||
|
|
||||||
[10]
|
[10]
|
||||||
name=UNKNOWN CLASS(10)
|
name=UNKNOWN CLASS(10)
|
||||||
|
|||||||
@ -30,6 +30,7 @@ DefScriptPackage::DefScriptPackage()
|
|||||||
|
|
||||||
DefScriptPackage::~DefScriptPackage()
|
DefScriptPackage::~DefScriptPackage()
|
||||||
{
|
{
|
||||||
|
if(_eventmgr)
|
||||||
delete _eventmgr;
|
delete _eventmgr;
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ DefReturnResult DefScriptPackage::SCpause(CmdSet& Set){
|
|||||||
}
|
}
|
||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCSendChatMessage(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");
|
logerror("Invalid Script call: SCSendChatMessage: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -88,7 +88,7 @@ DefReturnResult DefScriptPackage::SCSendChatMessage(CmdSet& Set){
|
|||||||
DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){
|
DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){
|
||||||
((PseuInstance*)parentMethod)->SaveAllCache();
|
((PseuInstance*)parentMethod)->SaveAllCache();
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
if(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid())
|
if(((PseuInstance*)parentMethod)->GetWSession())
|
||||||
{
|
{
|
||||||
str << "Cache saved. [ ";
|
str << "Cache saved. [ ";
|
||||||
str << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize();
|
str << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize();
|
||||||
@ -105,7 +105,7 @@ DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){
|
|||||||
DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){
|
DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){
|
||||||
if(Set.defaultarg.empty())
|
if(Set.defaultarg.empty())
|
||||||
return false;
|
return false;
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCEmote: WorldSession not valid");
|
logerror("Invalid Script call: SCEmote: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -141,7 +141,7 @@ DefReturnResult DefScriptPackage::SCfollow(CmdSet& Set)
|
|||||||
DefReturnResult DefScriptPackage::SCjoinchannel(CmdSet& Set){
|
DefReturnResult DefScriptPackage::SCjoinchannel(CmdSet& Set){
|
||||||
if(Set.defaultarg.empty())
|
if(Set.defaultarg.empty())
|
||||||
return false;
|
return false;
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCjoinchannel: WorldSession not valid");
|
logerror("Invalid Script call: SCjoinchannel: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -153,7 +153,7 @@ DefReturnResult DefScriptPackage::SCjoinchannel(CmdSet& Set){
|
|||||||
DefReturnResult DefScriptPackage::SCleavechannel(CmdSet& Set){
|
DefReturnResult DefScriptPackage::SCleavechannel(CmdSet& Set){
|
||||||
if(Set.defaultarg.empty())
|
if(Set.defaultarg.empty())
|
||||||
return false;
|
return false;
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCleavechannel: WorldSession not valid");
|
logerror("Invalid Script call: SCleavechannel: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -214,7 +214,7 @@ DefReturnResult DefScriptPackage::SCcastspell(CmdSet& Set)
|
|||||||
{
|
{
|
||||||
if(Set.defaultarg.empty())
|
if(Set.defaultarg.empty())
|
||||||
return false;
|
return false;
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCcastspell: WorldSession not valid");
|
logerror("Invalid Script call: SCcastspell: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -236,7 +236,7 @@ DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set){
|
|||||||
if(!id)
|
if(!id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCqueryitem: WorldSession not valid");
|
logerror("Invalid Script call: SCqueryitem: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -250,7 +250,7 @@ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set)
|
|||||||
// TODO: special targets: _self _pet _nearest ...
|
// TODO: special targets: _self _pet _nearest ...
|
||||||
DefReturnResult r;
|
DefReturnResult r;
|
||||||
|
|
||||||
if(!(((PseuInstance*)parentMethod)->GetWSession() && ((PseuInstance*)parentMethod)->GetWSession()->IsValid()))
|
if(!(((PseuInstance*)parentMethod)->GetWSession()))
|
||||||
{
|
{
|
||||||
logerror("Invalid Script call: SCtarget: WorldSession not valid");
|
logerror("Invalid Script call: SCtarget: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -360,7 +360,7 @@ DefReturnResult DefScriptPackage::SCGetScpValue(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCGetPlayerGuid(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");
|
logerror("Invalid Script call: SCGetPlayerGuid: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -380,7 +380,7 @@ DefReturnResult DefScriptPackage::SCGetPlayerGuid(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCGetName(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");
|
logerror("Invalid Script call: SCGetName: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -411,7 +411,7 @@ DefReturnResult DefScriptPackage::SCGetName(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCGetEntry(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");
|
logerror("Invalid Script call: SCGetEntry: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -433,7 +433,7 @@ DefReturnResult DefScriptPackage::SCGetEntry(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCGetObjectType(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");
|
logerror("Invalid Script call: SCGetObjectType: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -455,7 +455,7 @@ DefReturnResult DefScriptPackage::SCGetObjectType(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCObjectKnown(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");
|
logerror("Invalid Script call: SCObjectIsKnown: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
@ -489,7 +489,7 @@ DefReturnResult DefScriptPackage::SCGetScriptPerm(CmdSet& Set)
|
|||||||
|
|
||||||
DefReturnResult DefScriptPackage::SCGetItemProtoValue(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");
|
logerror("Invalid Script call: SCGetItemProtoValue: WorldSession not valid");
|
||||||
DEF_RETURN_ERROR;
|
DEF_RETURN_ERROR;
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
#include "DefScriptInterface.h"
|
#include "DefScriptInterface.h"
|
||||||
#include "Auth/BigNumber.h"
|
#include "Auth/BigNumber.h"
|
||||||
#include "DefScript/DefScript.h"
|
#include "DefScript/DefScript.h"
|
||||||
#include "Realm/RealmSocket.h"
|
#include "RealmSession.h"
|
||||||
#include "World/WorldSession.h"
|
#include "WorldSession.h"
|
||||||
#include "CacheHandler.h"
|
#include "CacheHandler.h"
|
||||||
#include "GUI/PseuGUI.h"
|
#include "GUI/PseuGUI.h"
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run)
|
|||||||
_stop=false;
|
_stop=false;
|
||||||
_fastquit=false;
|
_fastquit=false;
|
||||||
_startrealm=true;
|
_startrealm=true;
|
||||||
createWorldSession=false;
|
_createws=false;
|
||||||
_error=false;
|
_error=false;
|
||||||
_initialized=false;
|
_initialized=false;
|
||||||
|
|
||||||
@ -65,14 +65,19 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run)
|
|||||||
|
|
||||||
PseuInstance::~PseuInstance()
|
PseuInstance::~PseuInstance()
|
||||||
{
|
{
|
||||||
delete _wsession;
|
if(_cli)
|
||||||
if(GetConf()->enablecli && _cli)
|
|
||||||
{
|
{
|
||||||
_cli->stop();
|
_cli->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_rsession)
|
||||||
|
delete _rsession;
|
||||||
|
if(_wsession)
|
||||||
|
delete _wsession;
|
||||||
|
|
||||||
delete _scp;
|
delete _scp;
|
||||||
delete _conf;
|
delete _conf;
|
||||||
//delete _rsession; // deleted by SocketHandler!!!!!
|
|
||||||
log_close();
|
log_close();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -181,8 +186,7 @@ bool PseuInstance::Init(void) {
|
|||||||
|
|
||||||
void PseuInstance::Run(void)
|
void PseuInstance::Run(void)
|
||||||
{
|
{
|
||||||
do
|
|
||||||
{
|
|
||||||
if(!_initialized)
|
if(!_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -190,41 +194,42 @@ void PseuInstance::Run(void)
|
|||||||
{
|
{
|
||||||
logcritical("Realmlist address not set, can't connect.");
|
logcritical("Realmlist address not set, can't connect.");
|
||||||
SetError();
|
SetError();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
_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);
|
// for now: create the realmsession only on startup.
|
||||||
_sh.Select(1,0);
|
// may be extended to a script command later on.
|
||||||
}
|
// then try to connect
|
||||||
_startrealm=false; // the realm is started now
|
_rsession = new RealmSession(this);
|
||||||
|
_rsession->Connect();
|
||||||
|
_rsession->SendLogonChallenge();
|
||||||
|
|
||||||
while( (!_stop) && (!_startrealm) )
|
// this is the mainloop
|
||||||
|
while(!_stop)
|
||||||
{
|
{
|
||||||
Update();
|
Update();
|
||||||
if(_error)
|
if(_error)
|
||||||
_stop=true;
|
_stop=true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
while(GetConf()->reconnect && (!_stop));
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fastquit is defined if we clicked [X] (on windows)
|
||||||
if(_fastquit)
|
if(_fastquit)
|
||||||
{
|
{
|
||||||
log("Aborting Instance...");
|
log("Aborting Instance...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Shutting down instance...");
|
log("Shutting down instance...");
|
||||||
|
|
||||||
|
// if there was an error, better dont save, as the data might be damaged
|
||||||
|
if(!_error)
|
||||||
|
{
|
||||||
SaveAllCache();
|
SaveAllCache();
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
if(GetConf()->exitonerror == false && _error)
|
if(GetConf()->exitonerror == false && _error)
|
||||||
{
|
{
|
||||||
@ -238,45 +243,49 @@ void PseuInstance::Run(void)
|
|||||||
|
|
||||||
void PseuInstance::Update()
|
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
|
delete _rsession;
|
||||||
if(deleterealm)
|
_rsession = NULL;
|
||||||
{
|
|
||||||
deleterealm=false;
|
|
||||||
_rsession = NULL; // was deleted by SocketHandler already!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(createWorldSession && (!_wsession))
|
if(_wsession && _wsession->MustDie())
|
||||||
{
|
{
|
||||||
createWorldSession=false;
|
delete _wsession;
|
||||||
_wsession=new WorldSession(this);
|
_wsession = NULL;
|
||||||
}
|
}
|
||||||
if(_wsession && !_wsession->IsValid())
|
|
||||||
|
if(_createws)
|
||||||
{
|
{
|
||||||
|
_createws = false;
|
||||||
|
if(_wsession)
|
||||||
|
delete _wsession;
|
||||||
|
_wsession = new WorldSession(this);
|
||||||
_wsession->Start();
|
_wsession->Start();
|
||||||
}
|
}
|
||||||
if(_wsession && _wsession->IsValid())
|
|
||||||
|
// if we have no active sessions, we may reconnect
|
||||||
|
if((!_rsession) && (!_wsession) && GetConf()->reconnect)
|
||||||
{
|
{
|
||||||
try
|
logdetail("Waiting %u ms before reconnecting.",GetConf()->reconnect);
|
||||||
{
|
for(uint32 t = 0; t < GetConf()->reconnect && !this->Stopped(); t+=100) Sleep(100);
|
||||||
_wsession->Update(); // update the worldSESSION, which will update the worldsocket itself
|
this->Sleep(1000); // wait 1 sec before reconnecting
|
||||||
|
_rsession = new RealmSession(this);
|
||||||
|
_rsession->Connect();
|
||||||
|
_rsession->SendLogonChallenge(); // and login again
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
|
// update currently existing/active sessions
|
||||||
|
if(_rsession)
|
||||||
|
_rsession->Update();
|
||||||
|
if(_wsession)
|
||||||
|
try { _wsession->Update(); } catch (...)
|
||||||
{
|
{
|
||||||
logerror("Unhandled exception in WorldSession::Update()");
|
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();
|
GetScripts()->GetEventMgr()->Update();
|
||||||
|
|
||||||
this->Sleep(GetConf()->networksleeptime);
|
this->Sleep(GetConf()->networksleeptime);
|
||||||
@ -285,7 +294,7 @@ void PseuInstance::Update()
|
|||||||
void PseuInstance::SaveAllCache(void)
|
void PseuInstance::SaveAllCache(void)
|
||||||
{
|
{
|
||||||
//...
|
//...
|
||||||
if(GetWSession() && GetWSession()->IsValid())
|
if(GetWSession())
|
||||||
{
|
{
|
||||||
GetWSession()->plrNameCache.SaveToFile();
|
GetWSession()->plrNameCache.SaveToFile();
|
||||||
ItemProtoCache_WriteDataToCache(GetWSession());
|
ItemProtoCache_WriteDataToCache(GetWSession());
|
||||||
@ -311,7 +320,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
|
|||||||
accname=v.Get("ACCNAME");
|
accname=v.Get("ACCNAME");
|
||||||
accpass=v.Get("ACCPASS");
|
accpass=v.Get("ACCPASS");
|
||||||
exitonerror=(bool)atoi(v.Get("EXITONERROR").c_str());
|
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());
|
realmport=atoi(v.Get("REALMPORT").c_str());
|
||||||
clientversion_string=v.Get("CLIENTVERSION");
|
clientversion_string=v.Get("CLIENTVERSION");
|
||||||
clientbuild=atoi(v.Get("CLIENTBUILD").c_str());
|
clientbuild=atoi(v.Get("CLIENTBUILD").c_str());
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#include "Network/SocketHandler.h"
|
#include "Network/SocketHandler.h"
|
||||||
#include "SCPDatabase.h"
|
#include "SCPDatabase.h"
|
||||||
|
|
||||||
class RealmSocket;
|
class RealmSession;
|
||||||
class WorldSession;
|
class WorldSession;
|
||||||
class Sockethandler;
|
class Sockethandler;
|
||||||
class PseuInstanceRunnable;
|
class PseuInstanceRunnable;
|
||||||
@ -30,7 +30,7 @@ class PseuInstanceConf
|
|||||||
std::string accname;
|
std::string accname;
|
||||||
std::string accpass;
|
std::string accpass;
|
||||||
bool exitonerror;
|
bool exitonerror;
|
||||||
bool reconnect;
|
uint32 reconnect;
|
||||||
uint16 realmport;
|
uint16 realmport;
|
||||||
uint16 worldport;
|
uint16 worldport;
|
||||||
uint8 clientversion[3];
|
uint8 clientversion[3];
|
||||||
@ -67,7 +67,7 @@ class PseuInstance
|
|||||||
|
|
||||||
|
|
||||||
WorldSession *GetWSession(void) { return _wsession; }
|
WorldSession *GetWSession(void) { return _wsession; }
|
||||||
RealmSocket *GetRSession(void) { return _rsession; }
|
RealmSession *GetRSession(void) { return _rsession; }
|
||||||
PseuInstanceConf *GetConf(void) { return _conf; }
|
PseuInstanceConf *GetConf(void) { return _conf; }
|
||||||
DefScriptPackage *GetScripts(void) { return _scp; }
|
DefScriptPackage *GetScripts(void) { return _scp; }
|
||||||
PseuInstanceRunnable *GetRunnable(void) { return _runnable; }
|
PseuInstanceRunnable *GetRunnable(void) { return _runnable; }
|
||||||
@ -82,19 +82,19 @@ class PseuInstance
|
|||||||
bool Init();
|
bool Init();
|
||||||
void SaveAllCache(void);
|
void SaveAllCache(void);
|
||||||
void Stop(void) { _stop = true; }
|
void Stop(void) { _stop = true; }
|
||||||
|
bool Stopped(void) { return _stop; }
|
||||||
void SetFastQuit(bool q=true) { _fastquit=true; }
|
void SetFastQuit(bool q=true) { _fastquit=true; }
|
||||||
void Quit(void);
|
void Quit(void);
|
||||||
void Run(void);
|
void Run(void);
|
||||||
void Update(void);
|
void Update(void);
|
||||||
void Sleep(uint32 msecs);
|
void Sleep(uint32 msecs);
|
||||||
|
|
||||||
bool createWorldSession;
|
void CreateWorldSession(void) { _createws = true; }
|
||||||
bool deleterealm;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
PseuInstanceRunnable *_runnable;
|
PseuInstanceRunnable *_runnable;
|
||||||
RealmSocket *_rsession;
|
RealmSession *_rsession;
|
||||||
WorldSession *_wsession;
|
WorldSession *_wsession;
|
||||||
PseuInstanceConf *_conf;
|
PseuInstanceConf *_conf;
|
||||||
DefScriptPackage *_scp;
|
DefScriptPackage *_scp;
|
||||||
@ -103,6 +103,7 @@ class PseuInstance
|
|||||||
bool _stop,_fastquit;
|
bool _stop,_fastquit;
|
||||||
bool _startrealm;
|
bool _startrealm;
|
||||||
bool _error;
|
bool _error;
|
||||||
|
bool _createws;
|
||||||
BigNumber _sessionkey;
|
BigNumber _sessionkey;
|
||||||
char *_ver,*_ver_short;
|
char *_ver,*_ver_short;
|
||||||
SocketHandler _sh;
|
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 "common.h"
|
||||||
#include "PseuWoW.h"
|
#include "PseuWoW.h"
|
||||||
#include "ByteBuffer.h"
|
#include "ByteBuffer.h"
|
||||||
#include "Auth/Sha1.h"
|
#include "RealmSession.h"
|
||||||
#include "Auth/BigNumber.h"
|
|
||||||
#include "RealmSocket.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)
|
RealmSocket::RealmSocket(SocketHandler& h) : TcpSocket(h)
|
||||||
{
|
{
|
||||||
_instance=NULL;
|
_session = NULL;
|
||||||
_valid=false;
|
_ok = false;
|
||||||
_rport=3724;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RealmSocket::~RealmSocket()
|
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();
|
this->Close();
|
||||||
memset(_m2,0,20);
|
|
||||||
_key=0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealmSocket::_HandleRealmList(void)
|
bool RealmSocket::IsOk(void)
|
||||||
{
|
{
|
||||||
std::string realmAddr;
|
return _ok;
|
||||||
ByteBuffer realmbuf;
|
}
|
||||||
realmbuf.resize(ibuf.GetLength());
|
|
||||||
ibuf.Read((char*)realmbuf.contents(), ibuf.GetLength());
|
|
||||||
|
|
||||||
uint32 unk;
|
void RealmSocket::SetSession(RealmSession *rs)
|
||||||
uint16 len,count;
|
|
||||||
uint8 cmd;
|
|
||||||
realmbuf >> 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++)
|
|
||||||
{
|
{
|
||||||
realmbuf >> realms[i].icon;
|
_session = rs;
|
||||||
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
|
int RealmSocket::Close(void)
|
||||||
|
|
||||||
for(uint8 i=0;i<count;i++)
|
|
||||||
{
|
{
|
||||||
if(realms[i].name==GetInstance()->GetConf()->realmname)
|
_ok = false;
|
||||||
{
|
return TcpSocket::Close();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RealmSocket::OnRead(void)
|
void RealmSocket::OnRead(void)
|
||||||
{
|
{
|
||||||
TcpSocket::OnRead();
|
TcpSocket::OnRead();
|
||||||
bool known=false;
|
|
||||||
//printf("RealmSocket::OnRead() %u bytes\n",ibuf.GetLength());
|
|
||||||
if(!ibuf.GetLength())
|
|
||||||
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();
|
uint32 len = ibuf.GetLength();
|
||||||
char *data = new char[len];
|
logdev("RealmSocket::OnRead() %u bytes",len);
|
||||||
ibuf.Read(data,len); // if we have data crap left on the buf, delete it
|
if(!len)
|
||||||
logdebug("Data left on RealmSocket, Hexdump:");
|
return;
|
||||||
logdebug(toHexDump((uint8*)data,len).c_str());
|
ByteBuffer *pkt = new ByteBuffer(len);
|
||||||
|
uint8* data = new uint8[len];
|
||||||
|
ibuf.Read((char*)data,len);
|
||||||
|
pkt->append(data,len);
|
||||||
delete [] data;
|
delete [] data;
|
||||||
}
|
_session->AddToPktQueue(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RealmSocket::SendLogonChallenge(void)
|
RealmSession *RealmSocket::GetSession(void)
|
||||||
{
|
{
|
||||||
if(!this->Ready())
|
return _session;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealmSocket::OnAccept(void)
|
||||||
{
|
{
|
||||||
logerror("Error sending AUTH_LOGON_CHALLENGE, port is not ready!\n");
|
logdev("RealmSocket accepted.");
|
||||||
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());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PseuInstance *RealmSocket::GetInstance(void)
|
void RealmSocket::OnConnect(void)
|
||||||
{
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
logdetail("RealmSocket connected!");
|
logdetail("RealmSocket connected!");
|
||||||
SendLogonChallenge();
|
_ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealmSocket::OnConnectFailed(void)
|
void RealmSocket::OnConnectFailed(void)
|
||||||
{
|
{
|
||||||
logerror("Connecting to Realm failed!");
|
logerror("Connecting to Realm failed!");
|
||||||
|
_ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RealmSocket::OnException(void)
|
||||||
|
{
|
||||||
|
logerror("RealmSocket: Exception!");
|
||||||
|
_ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,52 +1,34 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _REALMSOCKET_H
|
#ifndef _REALMSOCKET_H
|
||||||
#define _REALMSOCKET_H
|
#define _REALMSOCKET_H
|
||||||
|
|
||||||
#include "Network/ResolvSocket.h"
|
#include "Network/TcpSocket.h"
|
||||||
#include "PseuWoW.h"
|
|
||||||
|
class RealmSession;
|
||||||
|
|
||||||
class RealmSocket : public TcpSocket
|
class RealmSocket : public TcpSocket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RealmSocket(SocketHandler &h);
|
RealmSocket(SocketHandler &h);
|
||||||
~RealmSocket();
|
~RealmSocket();
|
||||||
PseuInstance *GetInstance(void);
|
|
||||||
bool IsValid(void);
|
|
||||||
void SetInstance(PseuInstance*);
|
|
||||||
|
|
||||||
void SetHost(std::string);
|
RealmSession *GetSession(void);
|
||||||
void SetPort(uint16);
|
bool IsOk(void);
|
||||||
|
void SetSession(RealmSession*);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Start(void);
|
|
||||||
void Stop(void);
|
|
||||||
void Update(void);
|
void Update(void);
|
||||||
void SendLogonChallenge(void);
|
void SendLogonChallenge(void);
|
||||||
|
|
||||||
// dont use from outside!!
|
|
||||||
void _HandleRealmList(void);
|
|
||||||
void _HandleLogonProof(void);
|
|
||||||
void _HandleLogonChallenge(void);
|
|
||||||
|
|
||||||
void OnRead(void);
|
void OnRead(void);
|
||||||
void OnConnect(void);
|
void OnConnect(void);
|
||||||
void OnConnectFailed(void);
|
void OnConnectFailed(void);
|
||||||
|
void OnException(void);
|
||||||
|
void OnAccept(void);
|
||||||
|
int Close(void);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _ok;
|
||||||
|
RealmSession *_session;
|
||||||
|
|
||||||
uint16 _rport;
|
|
||||||
std::string _rhost;
|
|
||||||
uint8 _m2[20];
|
|
||||||
PseuInstance *_instance;
|
|
||||||
BigNumber _key;
|
|
||||||
bool _valid;
|
|
||||||
ByteBuffer _data;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
#include "Channel.h"
|
#include "Channel.h"
|
||||||
|
|
||||||
void WorldSession::SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to){
|
void WorldSession::SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to){
|
||||||
if((!_valid) || (!_logged) || msg.empty())
|
if((!_logged) || msg.empty())
|
||||||
return;
|
return;
|
||||||
WorldPacket packet;
|
WorldPacket packet;
|
||||||
packet<<type<<lang;
|
packet<<type<<lang;
|
||||||
|
|||||||
@ -8,21 +8,26 @@
|
|||||||
#include "WorldSocket.h"
|
#include "WorldSocket.h"
|
||||||
#include "RealmSocket.h"
|
#include "RealmSocket.h"
|
||||||
#include "Channel.h"
|
#include "Channel.h"
|
||||||
|
#include "RealmSession.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
|
|
||||||
|
struct OpcodeHandler
|
||||||
|
{
|
||||||
|
uint16 opcode;
|
||||||
|
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
WorldSession::WorldSession(PseuInstance *in)
|
WorldSession::WorldSession(PseuInstance *in)
|
||||||
{
|
{
|
||||||
logdebug("-> Starting WorldSession from instance 0x%X",in); // should never output a null ptr
|
logdebug("-> Starting WorldSession from instance 0x%X",in); // should never output a null ptr
|
||||||
_instance = in;
|
_instance = in;
|
||||||
_valid=_authed=_logged=false;
|
_mustdie=false;
|
||||||
_socket=new WorldSocket(_sh,this);
|
_logged=false;
|
||||||
|
_socket=NULL;
|
||||||
_myGUID=0; // i dont have a guid yet
|
_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);
|
_channels = new Channel(this);
|
||||||
|
_sh.SetAutoCloseSockets(false);
|
||||||
//...
|
//...
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,40 +35,43 @@ WorldSession::~WorldSession()
|
|||||||
{
|
{
|
||||||
WorldPacket *packet;
|
WorldPacket *packet;
|
||||||
// clear the queue
|
// clear the queue
|
||||||
while(!pktQueue.empty())
|
while(pktQueue.size())
|
||||||
{
|
{
|
||||||
packet = pktQueue.next();
|
packet = pktQueue.next();
|
||||||
delete packet;
|
delete packet;
|
||||||
}
|
}
|
||||||
_OnLeaveWorld();
|
|
||||||
|
|
||||||
|
if(_channels)
|
||||||
delete _channels;
|
delete _channels;
|
||||||
//delete _socket; the socket will be deleted by its handler!!
|
if(_socket)
|
||||||
|
delete _socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::Start(void)
|
void WorldSession::Start(void)
|
||||||
{
|
{
|
||||||
log("Connecting to '%s' on port %u",GetInstance()->GetConf()->worldhost.c_str(),GetInstance()->GetConf()->worldport);
|
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);
|
_socket->Open(GetInstance()->GetConf()->worldhost,GetInstance()->GetConf()->worldport);
|
||||||
if(GetInstance()->GetRSession())
|
if(GetInstance()->GetRSession())
|
||||||
{
|
{
|
||||||
GetInstance()->GetRSession()->SetCloseAndDelete(); // realm socket is no longer needed
|
GetInstance()->GetRSession()->SetMustDie(); // realm session is no longer needed
|
||||||
GetInstance()->deleterealm=true;
|
|
||||||
}
|
}
|
||||||
_valid=true;
|
|
||||||
_sh.Add(_socket);
|
_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;
|
logdetail("Loading Cache...");
|
||||||
}
|
plrNameCache.ReadFromFile(); // load names/guids of known players
|
||||||
|
ItemProtoCache_InsertDataToSession(this);
|
||||||
void WorldSession::SetSocket(WorldSocket *sock)
|
//...
|
||||||
{
|
|
||||||
_socket = sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::AddToPktQueue(WorldPacket *pkt)
|
void WorldSession::AddToPktQueue(WorldPacket *pkt)
|
||||||
@ -75,36 +83,24 @@ void WorldSession::SendWorldPacket(WorldPacket &pkt)
|
|||||||
{
|
{
|
||||||
if(GetInstance()->GetConf()->showmyopcodes)
|
if(GetInstance()->GetConf()->showmyopcodes)
|
||||||
logcustom(0,BROWN,"<< Opcode %u [%s]", pkt.GetOpcode(), GetOpcodeName(pkt.GetOpcode()));
|
logcustom(0,BROWN,"<< Opcode %u [%s]", pkt.GetOpcode(), GetOpcodeName(pkt.GetOpcode()));
|
||||||
|
if(_socket && _socket->IsOk())
|
||||||
_socket->SendWorldPacket(pkt);
|
_socket->SendWorldPacket(pkt);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("WorldSession: Can't send WorldPacket, socket doesn't exist or is not ready.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::Update(void)
|
void WorldSession::Update(void)
|
||||||
{
|
{
|
||||||
if (!IsValid())
|
if( _sh.GetCount() ) // the socketwil remove itself from the handler if it got closed
|
||||||
return;
|
|
||||||
|
|
||||||
if( _socket && _sh.GetCount() )
|
|
||||||
_sh.Select(0,0);
|
_sh.Select(0,0);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
/*if(!_socket)
|
|
||||||
{
|
|
||||||
if(_valid)
|
|
||||||
{
|
|
||||||
_deleteme = true;
|
|
||||||
}
|
|
||||||
_logged=_authed=_valid=false;
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(!_socket)
|
|
||||||
{
|
|
||||||
if(_valid)
|
|
||||||
{
|
|
||||||
this->Start();
|
|
||||||
}
|
|
||||||
_logged=_authed=_valid=false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpcodeHandler *table = _GetOpcodeHandlerTable();
|
OpcodeHandler *table = _GetOpcodeHandlerTable();
|
||||||
bool known=false;
|
bool known=false;
|
||||||
@ -212,7 +208,7 @@ void WorldSession::SetTarget(uint64 guid)
|
|||||||
|
|
||||||
void WorldSession::_OnEnterWorld(void)
|
void WorldSession::_OnEnterWorld(void)
|
||||||
{
|
{
|
||||||
if(!_logged)
|
if(!InWorld())
|
||||||
{
|
{
|
||||||
_logged=true;
|
_logged=true;
|
||||||
GetInstance()->GetScripts()->variables.Set("@inworld","true");
|
GetInstance()->GetScripts()->variables.Set("@inworld","true");
|
||||||
@ -223,7 +219,7 @@ void WorldSession::_OnEnterWorld(void)
|
|||||||
|
|
||||||
void WorldSession::_OnLeaveWorld(void)
|
void WorldSession::_OnLeaveWorld(void)
|
||||||
{
|
{
|
||||||
if(_logged)
|
if(InWorld())
|
||||||
{
|
{
|
||||||
_logged=false;
|
_logged=false;
|
||||||
GetInstance()->GetScripts()->RunScript("_leaveworld",NULL);
|
GetInstance()->GetScripts()->RunScript("_leaveworld",NULL);
|
||||||
@ -234,7 +230,7 @@ void WorldSession::_OnLeaveWorld(void)
|
|||||||
void WorldSession::_DoTimedActions(void)
|
void WorldSession::_DoTimedActions(void)
|
||||||
{
|
{
|
||||||
static clock_t pingtime=0;
|
static clock_t pingtime=0;
|
||||||
if(_logged)
|
if(InWorld())
|
||||||
{
|
{
|
||||||
if(pingtime < clock())
|
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
|
// 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);
|
_socket->InitCrypt(GetInstance()->GetSessionKey().AsByteArray(), 40);
|
||||||
|
|
||||||
_authed=true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
|
void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
|
||||||
@ -314,6 +308,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
|
|||||||
GetInstance()->SetError();
|
GetInstance()->SetError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_LoadCache(); // we are about to login, so we need cache data
|
||||||
logdetail("W: Chars in list: %u\n",num);
|
logdetail("W: Chars in list: %u\n",num);
|
||||||
for(unsigned int i=0;i<num;i++){
|
for(unsigned int i=0;i<num;i++){
|
||||||
recvPacket >> plr[i]._guid;
|
recvPacket >> plr[i]._guid;
|
||||||
|
|||||||
@ -13,14 +13,8 @@
|
|||||||
class WorldSocket;
|
class WorldSocket;
|
||||||
class WorldPacket;
|
class WorldPacket;
|
||||||
class Channel;
|
class Channel;
|
||||||
|
class RealmSession;
|
||||||
|
struct OpcodeHandler;
|
||||||
|
|
||||||
struct OpcodeHandler
|
|
||||||
{
|
|
||||||
uint16 opcode;
|
|
||||||
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class WorldSession
|
class WorldSession
|
||||||
@ -33,17 +27,13 @@ public:
|
|||||||
PseuInstance *GetInstance(void) { return _instance; }
|
PseuInstance *GetInstance(void) { return _instance; }
|
||||||
SCPDatabaseMgr& GetDBMgr(void) { return GetInstance()->dbmgr; }
|
SCPDatabaseMgr& GetDBMgr(void) { return GetInstance()->dbmgr; }
|
||||||
|
|
||||||
OpcodeHandler *_GetOpcodeHandlerTable(void) const;
|
|
||||||
|
|
||||||
void SetSocket(WorldSocket *sock);
|
|
||||||
|
|
||||||
void AddToPktQueue(WorldPacket *pkt);
|
void AddToPktQueue(WorldPacket *pkt);
|
||||||
void Connect(std::string addr,uint16 port);
|
|
||||||
void Update(void);
|
void Update(void);
|
||||||
void Start(void);
|
void Start(void);
|
||||||
bool IsValid(void) { return _valid; }
|
bool MustDie(void) { return _mustdie; }
|
||||||
bool DeleteMe(void);
|
void SetMustDie(void) { _mustdie = true; }
|
||||||
void SendWorldPacket(WorldPacket&);
|
void SendWorldPacket(WorldPacket&);
|
||||||
|
bool InWorld(void) { return _logged; }
|
||||||
|
|
||||||
void SetTarget(uint64 guid);
|
void SetTarget(uint64 guid);
|
||||||
uint64 GetTarget(void) { return GetMyChar()->GetTarget(); }
|
uint64 GetTarget(void) { return GetMyChar()->GetTarget(); }
|
||||||
@ -65,6 +55,7 @@ public:
|
|||||||
ObjMgr objmgr;
|
ObjMgr objmgr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
OpcodeHandler *_GetOpcodeHandlerTable(void) const;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
void _OnEnterWorld(void); // = login
|
void _OnEnterWorld(void); // = login
|
||||||
@ -99,10 +90,12 @@ private:
|
|||||||
void _ValuesUpdate(uint64 uguid, WorldPacket& recvPacket); // ...
|
void _ValuesUpdate(uint64 uguid, WorldPacket& recvPacket); // ...
|
||||||
void _QueryObjectInfo(uint64 guid);
|
void _QueryObjectInfo(uint64 guid);
|
||||||
|
|
||||||
|
void _LoadCache(void);
|
||||||
|
|
||||||
PseuInstance *_instance;
|
PseuInstance *_instance;
|
||||||
WorldSocket *_socket;
|
WorldSocket *_socket;
|
||||||
ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> pktQueue;
|
ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> pktQueue;
|
||||||
bool _valid,_authed,_logged,_deleteme; // world status
|
bool _logged,_mustdie; // world status
|
||||||
SocketHandler _sh; // handles the WorldSocket
|
SocketHandler _sh; // handles the WorldSocket
|
||||||
Channel *_channels;
|
Channel *_channels;
|
||||||
uint64 _myGUID;
|
uint64 _myGUID;
|
||||||
|
|||||||
@ -7,32 +7,40 @@ WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
|
|||||||
{
|
{
|
||||||
_session = s;
|
_session = s;
|
||||||
_gothdr = false;
|
_gothdr = false;
|
||||||
|
_ok=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldSocket::IsOk(void)
|
||||||
|
{
|
||||||
|
return _ok;
|
||||||
|
}
|
||||||
|
|
||||||
void WorldSocket::OnConnect()
|
void WorldSocket::OnConnect()
|
||||||
{
|
{
|
||||||
log("Connected to world server.\r\n");
|
log("Connected to world server.");
|
||||||
|
_ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSocket::OnConnectFailed()
|
void WorldSocket::OnConnectFailed()
|
||||||
{
|
{
|
||||||
logerror("WorldSocket::OnConnectFailed()\n");
|
logerror("Connecting to World Server failed!");
|
||||||
if(_session)
|
_ok = false;
|
||||||
_session->SetSocket(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSocket::OnDelete()
|
void WorldSocket::OnDelete()
|
||||||
{
|
{
|
||||||
log("Connection to world server has been closed.\n");
|
log("Connection to world server has been closed.");
|
||||||
if(_session)
|
_ok = false;
|
||||||
_session->SetSocket(NULL);
|
_session->SetMustDie(); // recreate the session if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSocket::OnException()
|
void WorldSocket::OnException()
|
||||||
{
|
{
|
||||||
DEBUG(logdebug("WorldSocket::OnException()"));
|
if(_ok)
|
||||||
this->SetCloseAndDelete();
|
{
|
||||||
|
logerror("WorldSocket::OnException()");
|
||||||
|
_ok = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSocket::OnRead()
|
void WorldSocket::OnRead()
|
||||||
@ -100,6 +108,8 @@ void WorldSocket::OnRead()
|
|||||||
|
|
||||||
void WorldSocket::SendWorldPacket(WorldPacket &pkt)
|
void WorldSocket::SendWorldPacket(WorldPacket &pkt)
|
||||||
{
|
{
|
||||||
|
if(!_ok)
|
||||||
|
return;
|
||||||
ClientPktHeader hdr;
|
ClientPktHeader hdr;
|
||||||
memset(&hdr,0,sizeof(ClientPktHeader));
|
memset(&hdr,0,sizeof(ClientPktHeader));
|
||||||
hdr.size = ntohs(pkt.size()+4);
|
hdr.size = ntohs(pkt.size()+4);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#ifndef _WORLDSOCKET_H
|
#ifndef _WORLDSOCKET_H
|
||||||
#define _WORLDSOCKET_H
|
#define _WORLDSOCKET_H
|
||||||
|
|
||||||
#include "Network/ResolvSocket.h"
|
#include "Network/TcpSocket.h"
|
||||||
#include "SysDefs.h"
|
#include "SysDefs.h"
|
||||||
|
|
||||||
class WorldSession;
|
class WorldSession;
|
||||||
@ -24,6 +24,7 @@ class WorldSocket : public TcpSocket
|
|||||||
public:
|
public:
|
||||||
WorldSocket(SocketHandler &h, WorldSession *s);
|
WorldSocket(SocketHandler &h, WorldSession *s);
|
||||||
WorldSession *GetSession(void) { return _session; }
|
WorldSession *GetSession(void) { return _session; }
|
||||||
|
bool IsOk();
|
||||||
|
|
||||||
void OnRead();
|
void OnRead();
|
||||||
void OnConnect();
|
void OnConnect();
|
||||||
@ -40,6 +41,7 @@ private:
|
|||||||
bool _gothdr; // true if only the header was recieved yet
|
bool _gothdr; // true if only the header was recieved yet
|
||||||
uint16 _opcode; // stores the last recieved opcode
|
uint16 _opcode; // stores the last recieved opcode
|
||||||
uint16 _remaining; // bytes amount of the next data packet
|
uint16 _remaining; // bytes amount of the next data packet
|
||||||
|
bool _ok;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -383,6 +383,12 @@
|
|||||||
<Filter
|
<Filter
|
||||||
Name="Realm"
|
Name="Realm"
|
||||||
Filter="">
|
Filter="">
|
||||||
|
<File
|
||||||
|
RelativePath=".\Client\Realm\RealmSession.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Client\Realm\RealmSession.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Client\Realm\RealmSocket.cpp">
|
RelativePath=".\Client\Realm\RealmSocket.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@ -123,6 +123,9 @@
|
|||||||
<Filter
|
<Filter
|
||||||
Name="Source Files"
|
Name="Source Files"
|
||||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
||||||
|
<File
|
||||||
|
RelativePath=".\shared\ByteBuffer.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\shared\common.h">
|
RelativePath=".\shared\common.h">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@ -55,6 +55,7 @@ SocketHandler::SocketHandler(StdLog *p)
|
|||||||
,m_bTryDirect(false)
|
,m_bTryDirect(false)
|
||||||
,m_resolv_id(0)
|
,m_resolv_id(0)
|
||||||
,m_resolver(NULL)
|
,m_resolver(NULL)
|
||||||
|
,m_auto_close_sockets(true)
|
||||||
{
|
{
|
||||||
FD_ZERO(&m_rfds);
|
FD_ZERO(&m_rfds);
|
||||||
FD_ZERO(&m_wfds);
|
FD_ZERO(&m_wfds);
|
||||||
@ -67,20 +68,24 @@ SocketHandler::~SocketHandler()
|
|||||||
if (m_resolver)
|
if (m_resolver)
|
||||||
m_resolver -> Quit();
|
m_resolver -> Quit();
|
||||||
if (!m_slave)
|
if (!m_slave)
|
||||||
|
{
|
||||||
|
if(m_auto_close_sockets)
|
||||||
{
|
{
|
||||||
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
||||||
{
|
{
|
||||||
Socket *p = (*it).second;
|
Socket *p = (*it).second;
|
||||||
|
if(p)
|
||||||
|
{
|
||||||
p -> Close();
|
p -> Close();
|
||||||
// p -> OnDelete(); // hey, I turn this back on. what's the worst that could happen??!!
|
p -> OnDelete();
|
||||||
// MinionSocket breaks, calling MinderHandler methods in OnDelete -
|
|
||||||
// MinderHandler is already gone when that happens...
|
|
||||||
if (p -> DeleteByHandler())
|
if (p -> DeleteByHandler())
|
||||||
{
|
{
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_resolver)
|
if (m_resolver)
|
||||||
delete m_resolver;
|
delete m_resolver;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,8 @@ class SocketHandler
|
|||||||
SocketHandler(StdLog * = NULL);
|
SocketHandler(StdLog * = NULL);
|
||||||
virtual ~SocketHandler();
|
virtual ~SocketHandler();
|
||||||
|
|
||||||
|
void SetAutoCloseSockets(bool x=true) { m_auto_close_sockets = x; }
|
||||||
|
|
||||||
/** Register StdLog object for error callback. */
|
/** Register StdLog object for error callback. */
|
||||||
void RegStdLog(StdLog *);
|
void RegStdLog(StdLog *);
|
||||||
void LogError(Socket *,const std::string&,int,const std::string&,loglevel_t = LOG_LEVEL_WARNING);
|
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;
|
int m_resolv_id;
|
||||||
ResolvServer *m_resolver;
|
ResolvServer *m_resolver;
|
||||||
port_t m_resolver_port;
|
port_t m_resolver_port;
|
||||||
|
bool m_auto_close_sockets;
|
||||||
};
|
};
|
||||||
#endif // _SOCKETHANDLER_H
|
#endif // _SOCKETHANDLER_H
|
||||||
|
|||||||
@ -257,12 +257,11 @@ void ExtractMaps(void)
|
|||||||
fh.write((char*)bb.contents(),bb.size());
|
fh.write((char*)bb.contents(),bb.size());
|
||||||
fh.close();
|
fh.close();
|
||||||
extr++;
|
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;
|
extrtotal+=extr;
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user