* 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:
False.Genesis 2007-05-11 20:55:38 +00:00
parent 95353eb132
commit 6c4ae79a87
20 changed files with 796 additions and 638 deletions

View File

@ -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

View File

@ -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)

View File

@ -30,6 +30,7 @@ DefScriptPackage::DefScriptPackage()
DefScriptPackage::~DefScriptPackage() DefScriptPackage::~DefScriptPackage()
{ {
if(_eventmgr)
delete _eventmgr; delete _eventmgr;
Clear(); Clear();
} }

View File

@ -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;

View File

@ -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());

View File

@ -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;

View 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!");
}
}

View 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

View File

@ -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; _session = rs;
realmbuf >> cmd >> len >> unk >> count; }
// no realm? int RealmSocket::Close(void)
if(count==0) {
return; _ok = false;
return TcpSocket::Close();
// 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;
} }
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;
{
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());
} }
PseuInstance *RealmSocket::GetInstance(void) void RealmSocket::OnAccept(void)
{ {
return _instance; logdev("RealmSocket accepted.");
} }
void RealmSocket::_HandleLogonChallenge(void) void RealmSocket::OnConnect(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;
}

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}; };

View File

@ -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>

View 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>

View 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;
} }

View File

@ -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

View File

@ -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");
} }