mojo_client/src/Client/Realm/RealmSession.cpp
false_genesis 76ebbe5cf3 * rewrote the SCP data storage. note that all database files must now be placed in a directory added with "AddDBPath <path>" and must contain a #dbname tag. the db now converts SCP (text) to SCC (binary) files, which increases access speed a lot. also less RAM used in most cases.
* replaced "LoadSCP" func with "LoadDB <dbname>" (different syntax!); removed all other scp db related funcs except "getscpvalue"
* the GUI can now show texts stored in databases
* added displaying status to SceneLogin
* misc fixes/cleanups
2008-04-19 23:45:37 +00:00

742 lines
25 KiB
C++

#include "common.h"
#include "Auth/Sha1.h"
#include "Auth/BigNumber.h"
#include "PseuWoW.h"
#include "RealmSocket.h"
#include "RealmSession.h"
enum AuthCmd
{
//AUTH_NO_CMD = 0xFF,
AUTH_LOGON_CHALLENGE = 0x00,
AUTH_LOGON_PROOF = 0x01,
//AUTH_RECONNECT_CHALLENGE = 0x02,
//AUTH_RECONNECT_PROOF = 0x03,
//update srv =4
REALM_LIST = 0x10,
XFER_INITIATE = 0x30,
XFER_DATA = 0x31,
XFER_ACCEPT = 0x32,
XFER_RESUME = 0x33,
XFER_CANCEL = 0x34
};
enum eAuthResults
{
REALM_AUTH_SUCCESS = 0,
REALM_AUTH_FAILURE=0x01, ///< Unable to connect
REALM_AUTH_UNKNOWN1=0x02, ///< Unable to connect
REALM_AUTH_ACCOUNT_BANNED=0x03, ///< This <game> account has been closed and is no longer available for use. Please go to <site>/banned.html for further information.
REALM_AUTH_NO_MATCH=0x04, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see <site> for more information
REALM_AUTH_UNKNOWN2=0x05, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see <site> for more information
REALM_AUTH_ACCOUNT_IN_USE=0x06, ///< This account is already logged into <game>. Please check the spelling and try again.
REALM_AUTH_PREPAID_TIME_LIMIT=0x07, ///< You have used up your prepaid time for this account. Please purchase more to continue playing
REALM_AUTH_SERVER_FULL=0x08, ///< Could not log in to <game> at this time. Please try again later.
REALM_AUTH_WRONG_BUILD_NUMBER=0x09, ///< Unable to validate game version. This may be caused by file corruption or interference of another program. Please visit <site> for more information and possible solutions to this issue.
REALM_AUTH_UPDATE_CLIENT=0x0a, ///< Downloading
REALM_AUTH_UNKNOWN3=0x0b, ///< Unable to connect
REALM_AUTH_ACCOUNT_FREEZED=0x0c, ///< This <game> account has been temporarily suspended. Please go to <site>/banned.html for further information
REALM_AUTH_UNKNOWN4=0x0d, ///< Unable to connect
REALM_AUTH_UNKNOWN5=0x0e, ///< Connected.
REALM_AUTH_PARENTAL_CONTROL=0x0f ///< Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at <site>
};
#define ChunkSize 2048
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 unk2;
uint8 error;
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;
_filetransfer = false;
_file_size = 0;
_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;
logdebug("RealmSession: Must die now.");
}
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},
{XFER_INITIATE,&RealmSession::_HandleTransferInit},
{XFER_DATA,&RealmSession::_HandleTransferData},
{0,NULL}
};
return table;
}
void RealmSession::AddToPktQueue(ByteBuffer *pkt)
{
pktQueue.add(pkt);
}
void RealmSession::Update(void)
{
AuthHandler *table = _GetAuthHandlerTable();
ByteBuffer *pkt;
uint8 cmd;
bool valid = true;
if( _sh.GetCount() ) // the socket will remove itself from the handler if it got closed
_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();
}
}
while(pktQueue.size())
{
valid = false;
pkt = pktQueue.next();
cmd = (*pkt)[0];
// this is a dirty hack for oversize/splitted up packets that are buffered wrongly by realmd
if(_filetransfer)
{
_HandleTransferData(*pkt);
}
// if we dont expect a file transfer select packets as usual
else
{
for(uint8 i=0;table[i].handler!=NULL;i++)
{
if(table[i].cmd==cmd)
{
valid = true;
(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;
}
break;
}
}
if(!valid)
{
logerror("Invalid realm packet, unknown opcode 0x%X",cmd);
//logerror(toHexDump((uint8*)pkt->contents(),pkt->size()).c_str());
}
}
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",DefScriptTools::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::SetLogonData(void)
{
_accname=GetInstance()->GetConf()->accname;
_accpass=GetInstance()->GetConf()->accpass;
}
void RealmSession::SendLogonChallenge(void)
{
if(!_socket)
{
logerror("Can't send logon challenge, socket doesn't exist");
return;
}
if( _accname.empty() || GetInstance()->GetConf()->clientversion_string.empty()
|| GetInstance()->GetConf()->clientbuild==0 || GetInstance()->GetConf()->clientlang.empty() )
{
logcritical("Missing data, can't send Login challenge to Realm Server! (check your conf files)");
GetInstance()->SetError();
return;
}
if(PseuGUI *gui = GetInstance()->GetGUI())
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_LOGGING_IN);
std::string acc = stringToUpper(_accname);
ByteBuffer packet;
packet << (uint8)AUTH_LOGON_CHALLENGE;
packet << (uint8)6;
packet << (uint8)(acc.length()+30); // length of the rest of the packet
packet << (uint8)0;
packet << "WoW";
packet.append(GetInstance()->GetConf()->clientversion,3); // 1.12.2 etc
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->GetMyIP(); // 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);
logdebug("Packet Sent");
}
void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
{
PseuGUI *gui = GetInstance()->GetGUI();
logdebug("RealmSocket: Got AUTH_LOGON_CHALLENGE [%u of %u bytes]",pkt.size(),sizeof(sAuthLogonChallenge_S));
if(pkt.size() < 3)
{
logerror("AUTH_LOGON_CHALLENGE: Recieved incorrect/unknown packet. Hexdump:");
DumpInvalidPacket(pkt);
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR);
return;
}
sAuthLogonChallenge_S lc;
lc.error = pkt[2]; // pre-set error (before copying whole challenge)
switch (lc.error)
{
case 4:
logerror("Realm Server did not find account \"%s\"!",_accname.c_str());
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_ACC_NOT_FOUND);
break;
case 6:
logerror("Account \"%s\" is already logged in!",_accname.c_str());
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_ALREADY_CONNECTED);
break;
case 9:
logerror("Realm Server doesn't accept this version!");
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_WRONG_VERSION);
break;
case 0:
{
pkt.read((uint8*)&lc, sizeof(sAuthLogonChallenge_S));
logdetail("Login successful, now calculating proof packet...");
if(PseuGUI *gui = GetInstance()->GetGUI())
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_AUTHENTICATING);
// 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( _accname );
std::string _authstr=stringToUpper( user +":"+_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)
{
PseuGUI *gui = GetInstance()->GetGUI();
logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),26);
if(pkt.size() < 2)
{
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
DumpInvalidPacket(pkt);
DieOrReconnect(true);
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR);
return;
}
uint8 error = pkt[1];
// handle error codes
switch(error)
{
case REALM_AUTH_UPDATE_CLIENT:
log("The realm server requested client update.");
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_WRONG_VERSION);
DieOrReconnect(true);
return;
case REALM_AUTH_NO_MATCH:
case REALM_AUTH_UNKNOWN2:
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_AUTH_FAILED);
logerror("Wrong password or invalid account information or authentication error");
DieOrReconnect(true);
return;
// cover all other cases. continue only if success.
default:
if(error != REALM_AUTH_SUCCESS)
{
logerror("AUTH_LOGON_PROOF: unk error = 0x%X",error);
if(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR);
pkt.rpos(2);
DieOrReconnect(true);
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))
{
if(PseuGUI *gui = GetInstance()->GetGUI())
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_REQ_REALM);
// 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(gui)
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_AUTH_FAILED);
DieOrReconnect(true);
}
}
void RealmSession::_HandleTransferInit(ByteBuffer& pkt)
{
_filebuf.clear();
_transbuf.clear();
_file_done = 0;
_filetransfer = true;
uint8 cmd;
uint8 type_size;
uint8 *type_str;
pkt >> cmd >> type_size;
type_str = new uint8[type_size+1];
type_str[type_size] = 0;
pkt.read(type_str,type_size);
pkt >> _file_size;
pkt.read(_file_md5,MD5_DIGEST_LENGTH);
logcustom(0,GREEN,"TransferInit [%s]: File size: "I64FMTD" KB (MD5: %s)", (char*)type_str, _file_size / 1024L, toHexDump(&_file_md5[0],MD5_DIGEST_LENGTH,false).c_str());
if(PseuGUI *gui = GetInstance()->GetGUI())
gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_FILE_TRANSFER);
delete [] type_str;
ByteBuffer bb(1);
bb << uint8(XFER_ACCEPT);
SendRealmPacket(bb);
logdebug("XFER_ACCEPT sent");
}
void RealmSession::_HandleTransferData(ByteBuffer& pkt)
{
if(!_file_size)
{
logerror("Realm server attempted to transfer a file, but didn't init!");
DieOrReconnect(false);
return;
}
uint8 cmd;
uint16 size;
uint8 *data;
_transbuf.append(pkt.contents(),pkt.size()); // append everything to the transfer buffer, which may also store incomplete bytes from the packet before
pkt.rpos(pkt.size()); // set rpos to the end of the packet to indicate that we used all data
logdev("transbuf size=%u rpos=%u diff=%u",_transbuf.size(),_transbuf.rpos(),_transbuf.size() - _transbuf.rpos());
while( _transbuf.size() - _transbuf.rpos() >= 3) // 3 = sizeof(uint32)+sizeof(uint8)
{
_transbuf >> cmd >> size;
if(_transbuf.size()-_transbuf.rpos() < size)
{
_transbuf.rpos(_transbuf.rpos()-3); // read the header next time again
break; // packet parts missing, continue after recieving next packet
}
data = new uint8[size];
_transbuf.read(data,size);
_filebuf.append(data,size);
_file_done += size;
delete [] data;
float pct = ((float)_file_done / (float)_file_size * 100.0f);
// use better output formatting in debug level
if(GetInstance()->GetConf()->debug >= 2)
logdebug("Got data packet, %u data bytes. [%.2f%% done] cmd 0x%X",size,pct,cmd);
else
{
_log_setcolor(true,GREEN);
printf("\r[%.2f%% done]",pct);
_log_resetcolor(true);
}
}
// finalize file
if(_file_done >= _file_size)
{
log("");
log("File transfer finished.");
_filetransfer = false;
MD5Hash md5h;
md5h.Update((uint8*)_filebuf.contents(),_filebuf.size());
md5h.Finalize();
std::string md5hex = toHexDump(md5h.GetDigest(),md5h.GetLength(),false);
logdebug("MD5 hash: %s", md5hex.c_str());
if(!memcmp(_file_md5, md5h.GetDigest(), md5h.GetLength()))
{
std::fstream fh;
char namebuf[100];
sprintf(namebuf,"%u_%s.mpq",GetInstance()->GetConf()->clientbuild,GetInstance()->GetConf()->clientlang.c_str());
fh.open(namebuf,std::ios_base::out | std::ios_base::binary);
if(fh.is_open())
{
fh.write((const char*)_filebuf.contents(),_filebuf.size());
fh.close();
log("File saved as \"%s\"",namebuf);
}
else
{
logerror("Could not save \"%s\"",namebuf);
}
}
else
{
logerror("File corruption! Transfer failed! (MD5: %s",md5hex.c_str());
}
_transbuf.clear();
// client sends cancel after successful file transfer also
ByteBuffer bb(1);
bb << uint8(XFER_CANCEL);
SendRealmPacket(bb);
log("Now modify your conf files and restart PseuWoW.");
for(int8 x = 3; x > -1; x--) // add little delay
{
printf("exiting in... [%u]\r",x);
GetInstance()->Sleep(1000);
}
SetMustDie();
GetInstance()->Stop();
}
}
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!");
}
}
// err=true will close PseuWoW if ExitOnError=1
void RealmSession::DieOrReconnect(bool err)
{
if(GetInstance()->GetConf()->reconnect)
SetMustDie();
else if(err)
{
SetMustDie();
GetInstance()->SetError();
}
}
bool RealmSession::SocketGood(void)
{
return _socket && _socket->IsOk();
}