* implemented patch download supplied by realm server (does NOT yet support resuming a download)
* fixed a few bugs in RealmSession (ticket #14, thx bLuma) * fixed a mistake in DefScript.cpp added in prev commit. * added wrapper class for MD5 hashes
This commit is contained in:
parent
71b17e7ced
commit
97f5d0da98
@ -275,7 +275,7 @@ bool DefScriptPackage::LoadScriptFromFile(std::string fn){
|
||||
DeleteScript(curScript->GetName());
|
||||
sn = stringToLower(value);
|
||||
_UpdateOrCreateScriptByName(sn);
|
||||
_DEFSC_DEBUG_LOG("DefScript: now loading '%s'\n",sn.c_str());
|
||||
_DEFSC_DEBUG(printf("DefScript: now loading '%s'\n",sn.c_str()));
|
||||
curScript=Script[sn];
|
||||
}
|
||||
else if(line=="debug")
|
||||
|
||||
@ -92,7 +92,6 @@ public:
|
||||
inline void Stop(void) { _stop = true; }
|
||||
inline bool Stopped(void) { return _stop; }
|
||||
inline void SetFastQuit(bool q=true) { _fastquit=true; }
|
||||
void Quit(void);
|
||||
void Run(void);
|
||||
void Update(void);
|
||||
void Sleep(uint32 msecs);
|
||||
|
||||
@ -7,11 +7,42 @@
|
||||
|
||||
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
|
||||
@ -42,8 +73,8 @@ struct AuthHandler
|
||||
struct sAuthLogonChallenge_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 unk2;
|
||||
uint8 error;
|
||||
uint8 B[32];
|
||||
uint8 g_len;
|
||||
uint8 g[1];
|
||||
@ -66,6 +97,8 @@ RealmSession::RealmSession(PseuInstance* instance)
|
||||
_instance = instance;
|
||||
_socket = NULL;
|
||||
_mustdie = false;
|
||||
_filetransfer = false;
|
||||
_file_size = 0;
|
||||
_sh.SetAutoCloseSockets(false);
|
||||
}
|
||||
|
||||
@ -121,6 +154,8 @@ AuthHandler *RealmSession::_GetAuthHandlerTable(void) const
|
||||
{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;
|
||||
@ -136,6 +171,7 @@ 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);
|
||||
@ -149,12 +185,23 @@ void RealmSession::Update(void)
|
||||
|
||||
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())
|
||||
{
|
||||
@ -165,11 +212,17 @@ void RealmSession::Update(void)
|
||||
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)
|
||||
@ -251,7 +304,7 @@ 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!");
|
||||
logcritical("Missing data, can't send Login challenge to Realm Server! (check your conf files)");
|
||||
GetInstance()->SetError();
|
||||
return;
|
||||
}
|
||||
@ -279,7 +332,7 @@ void RealmSession::SendLogonChallenge(void)
|
||||
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))
|
||||
if(pkt.size() < 3)
|
||||
{
|
||||
logerror("AUTH_LOGON_CHALLENGE: Recieved incorrect/unknown packet. Hexdump:");
|
||||
DumpInvalidPacket(pkt);
|
||||
@ -287,22 +340,23 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
|
||||
}
|
||||
|
||||
sAuthLogonChallenge_S lc;
|
||||
pkt.read((uint8*)&lc, sizeof(sAuthLogonChallenge_S));
|
||||
lc.error = pkt[2]; // pre-set error (before copying whole challenge)
|
||||
|
||||
switch (lc.error)
|
||||
{
|
||||
case 4:
|
||||
log("Realm Server did not find account \"%s\"!",GetInstance()->GetConf()->accname.c_str());
|
||||
logerror("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());
|
||||
logerror("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!");
|
||||
logerror("Realm Server doesn't accept this version!");
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
pkt.read((uint8*)&lc, sizeof(sAuthLogonChallenge_S));
|
||||
logdetail("Login successful, now calculating proof packet...");
|
||||
|
||||
// now lets start calculating
|
||||
@ -441,7 +495,7 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
|
||||
void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
|
||||
{
|
||||
logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]\n",pkt.size(),26);
|
||||
if(pkt.size() < 26)
|
||||
if(pkt.size() < 2)
|
||||
{
|
||||
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
|
||||
DumpInvalidPacket(pkt);
|
||||
@ -449,6 +503,32 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
|
||||
SetMustDie();
|
||||
return;
|
||||
}
|
||||
uint8 error = pkt[1];
|
||||
|
||||
// handle error codes
|
||||
switch(error)
|
||||
{
|
||||
case REALM_AUTH_UPDATE_CLIENT:
|
||||
log("The realm server requested client update.");
|
||||
return;
|
||||
|
||||
case REALM_AUTH_NO_MATCH:
|
||||
case REALM_AUTH_UNKNOWN2:
|
||||
logerror("Wrong password or invalid account information or authentication error");
|
||||
return;
|
||||
|
||||
// cover all other cases. continue only if success.
|
||||
default:
|
||||
if(error != REALM_AUTH_SUCCESS)
|
||||
{
|
||||
logerror("AUTH_LOGON_PROOF: unk error = 0x%X",error);
|
||||
pkt.rpos(2);
|
||||
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);
|
||||
@ -473,6 +553,126 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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!");
|
||||
SetMustDie();
|
||||
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())
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define REALMSESSION_H
|
||||
|
||||
#include "common.h"
|
||||
#include "Auth/MD5Hash.h"
|
||||
|
||||
struct AuthHandler;
|
||||
class RealmSocket;
|
||||
@ -26,6 +27,8 @@ private:
|
||||
void _HandleRealmList(ByteBuffer&);
|
||||
void _HandleLogonProof(ByteBuffer&);
|
||||
void _HandleLogonChallenge(ByteBuffer&);
|
||||
void _HandleTransferInit(ByteBuffer&);
|
||||
void _HandleTransferData(ByteBuffer&);
|
||||
AuthHandler *_GetAuthHandlerTable(void) const;
|
||||
void SendRealmPacket(ByteBuffer&);
|
||||
void DumpInvalidPacket(ByteBuffer&);
|
||||
@ -38,7 +41,11 @@ private:
|
||||
RealmSession *_session;
|
||||
BigNumber _key;
|
||||
bool _mustdie;
|
||||
|
||||
bool _filetransfer;
|
||||
uint8 _file_md5[MD5_DIGEST_LENGTH];
|
||||
uint64 _file_done, _file_size;
|
||||
ByteBuffer _filebuf;
|
||||
ByteBuffer _transbuf; // stores parts of unfinished packets
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -298,6 +298,9 @@
|
||||
<File
|
||||
RelativePath=".\shared\Auth\md5.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\shared\Auth\MD5Hash.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\shared\Auth\Sha1.cpp">
|
||||
</File>
|
||||
|
||||
45
src/shared/Auth/MD5Hash.h
Normal file
45
src/shared/Auth/MD5Hash.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef MD5HASH_H
|
||||
#define MD5HASH_H
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
|
||||
#include "Auth/md5.h"
|
||||
|
||||
class MD5Hash
|
||||
{
|
||||
public:
|
||||
MD5Hash()
|
||||
{
|
||||
md5_init(&_state);
|
||||
memset(_digest,0,MD5_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
void Update(uint8 *buf,uint32 len)
|
||||
{
|
||||
md5_append(&_state,buf,len);
|
||||
}
|
||||
|
||||
void Update(std::string s)
|
||||
{
|
||||
Update((uint8*)s.c_str(),s.length());
|
||||
}
|
||||
|
||||
void Finalize(void)
|
||||
{
|
||||
md5_finish(&_state,_digest);
|
||||
}
|
||||
|
||||
uint8 *GetDigest(void)
|
||||
{
|
||||
return _digest;
|
||||
}
|
||||
|
||||
uint8 GetLength(void) { return MD5_DIGEST_LENGTH; }
|
||||
|
||||
private:
|
||||
md5_state_t _state;
|
||||
uint8 _digest[MD5_DIGEST_LENGTH];
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user