Initial MSVC 2008 projects workspace
This commit is contained in:
115
L2C_Server/net/GameClient/GameClient.cpp
Normal file
115
L2C_Server/net/GameClient/GameClient.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "pch.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
|
||||
GameClient::GameClient( SOCKET s_cl, const char *ip, int port )
|
||||
{
|
||||
setUnused();
|
||||
if( ip )
|
||||
{
|
||||
strncpy( m_ip, ip, 16 ); m_ip[16] = 0;
|
||||
l2c_ansi_to_unicode( m_ip, m_wip, 16 );
|
||||
}
|
||||
m_port = port;
|
||||
m_sock = s_cl;
|
||||
m_was_force_disconnected = false;
|
||||
m_flagStop = m_isRunning = false;
|
||||
swprintf( m_tostring, 128, L"Client [IP: %s:%d]", m_wip, m_port );
|
||||
m_ph = new ClientPacketHandler( this );
|
||||
}
|
||||
|
||||
GameClient::~GameClient()
|
||||
{
|
||||
if( m_ph )
|
||||
{
|
||||
delete m_ph;
|
||||
m_ph = NULL;
|
||||
}
|
||||
if( m_obf )
|
||||
{
|
||||
delete m_obf;
|
||||
m_obf = NULL;
|
||||
}
|
||||
if( m_player )
|
||||
{
|
||||
delete m_player; // really? some notification?
|
||||
m_player = NULL;
|
||||
}
|
||||
setUnused();
|
||||
}
|
||||
|
||||
void GameClient::setUnused()
|
||||
{
|
||||
// zero our members
|
||||
m_account[0] = 0;
|
||||
memset( m_playKey, 0, sizeof(m_playKey) );
|
||||
memset( m_loginKey, 0, sizeof(m_loginKey) );
|
||||
m_ip[0] = 0;
|
||||
m_wip[0] = 0;
|
||||
m_port = 0;
|
||||
m_sock = INVALID_SOCKET;
|
||||
m_tostring[0] = 0;
|
||||
m_state = CLIENT_STATE_OFFLINE;
|
||||
m_xor_enabled = false;
|
||||
memset( m_xor_key_recv, 0, sizeof(m_xor_key_recv) );
|
||||
memset( m_xor_key_send, 0, sizeof(m_xor_key_send) );
|
||||
m_protocolIsOk = false;
|
||||
m_netStats.clear();
|
||||
m_opcodeObfuscationSeed = 0;
|
||||
m_obf = NULL;
|
||||
m_player = NULL;
|
||||
}
|
||||
|
||||
const wchar_t *GameClient::getAccount() const { return (const wchar_t *)m_account; }
|
||||
void GameClient::getPlayKey( unsigned char *buffer ) const { memcpy( buffer, m_playKey, 8 ); }
|
||||
void GameClient::getLoginKey( unsigned char *buffer ) const { memcpy( buffer, m_loginKey, 8 ); }
|
||||
const char *GameClient::getIpA() const { return (const char *)m_ip; }
|
||||
const wchar_t *GameClient::getIpW() const { return (const wchar_t *)m_wip; }
|
||||
int GameClient::getPort() const { return m_port; }
|
||||
const wchar_t *GameClient::toString() const { return (const wchar_t *)m_tostring; }
|
||||
ClientState GameClient::getState() const { return m_state; }
|
||||
bool GameClient::isProtocolOk() const { return m_protocolIsOk; }
|
||||
const GameClientNetStats *GameClient::getNetStats() const { return &m_netStats; }
|
||||
unsigned int GameClient::getOpcodeObfuscationSeed() const { return m_opcodeObfuscationSeed; }
|
||||
L2PCodeObfuscator *GameClient::getOpcodeObfuscator() { return m_obf; }
|
||||
GamePlayer *GameClient::getPlayer() { return m_player; }
|
||||
|
||||
void GameClient::setAccount( const wchar_t *acc )
|
||||
{
|
||||
if( acc )
|
||||
{
|
||||
wcsncpy( m_account, acc, sizeof(m_account)/sizeof(wchar_t) );
|
||||
m_account[sizeof(m_account)/sizeof(wchar_t) - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::setSessionKeys( const unsigned char *playKey, const unsigned char *loginKey )
|
||||
{
|
||||
memcpy( m_playKey, playKey, 8 );
|
||||
memcpy( m_loginKey, loginKey, 8 );
|
||||
}
|
||||
|
||||
void GameClient::setProtocolOk( bool b ) { m_protocolIsOk = b; }
|
||||
|
||||
void GameClient::setOpcodeObfuscationSeed( unsigned int s )
|
||||
{
|
||||
m_opcodeObfuscationSeed = s;
|
||||
if( m_obf )
|
||||
{
|
||||
delete m_obf;
|
||||
m_obf = NULL;
|
||||
}
|
||||
if( s != 0 )
|
||||
{
|
||||
m_obf = new L2PCodeObfuscator();
|
||||
m_obf->init_tables( m_opcodeObfuscationSeed );
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::setPlayer( GamePlayer *newPlayer, bool changeState, ClientState newState )
|
||||
{
|
||||
if( m_player ) delete m_player;
|
||||
m_player = NULL;
|
||||
if( newPlayer ) m_player = newPlayer;
|
||||
if( changeState ) m_state = newState;
|
||||
}
|
78
L2C_Server/net/GameClient/GameClient.h
Normal file
78
L2C_Server/net/GameClient/GameClient.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include "enums.h"
|
||||
#include "net/ClientPacketHandler.h"
|
||||
#include "GameClientNetStats.h"
|
||||
#include "world/model/character/GamePlayer.h"
|
||||
|
||||
class GameClient
|
||||
{
|
||||
public:
|
||||
GameClient( SOCKET s_cl, const char *ip, int port );
|
||||
virtual ~GameClient();
|
||||
virtual void setUnused();
|
||||
|
||||
public:
|
||||
const wchar_t *getAccount() const;
|
||||
void getPlayKey( unsigned char *buffer ) const;
|
||||
void getLoginKey( unsigned char *buffer ) const;
|
||||
const char *getIpA() const;
|
||||
const wchar_t *getIpW() const;
|
||||
int getPort() const;
|
||||
const wchar_t *toString() const;
|
||||
ClientState getState() const;
|
||||
bool isProtocolOk() const;
|
||||
const GameClientNetStats *getNetStats() const;
|
||||
unsigned int getOpcodeObfuscationSeed() const;
|
||||
L2PCodeObfuscator *getOpcodeObfuscator();
|
||||
GamePlayer *getPlayer();
|
||||
|
||||
public:
|
||||
void setAccount( const wchar_t *acc );
|
||||
void setSessionKeys( const unsigned char *playKey, const unsigned char *loginKey );
|
||||
void setProtocolOk( bool b ) ;
|
||||
void setOpcodeObfuscationSeed( unsigned int s );
|
||||
void setPlayer( GamePlayer *newPlayer, bool changeState = false, ClientState newState = CLIENT_STATE_OFFLINE );
|
||||
|
||||
public:
|
||||
// begins client processing, starts thread
|
||||
bool startThread();
|
||||
// stops all client activity, disconnects socket, optionally sends packet before client close
|
||||
void disconnectForceAndWaitThreadToStop( bool server_shutdown, bool reasonDualLogin );
|
||||
// signal thread to stop (no wait to stop)
|
||||
void signalThreadStop( bool setMarkToDeleteSelfAndCleanupClientPool );
|
||||
bool sendPacket( L2GamePacket *pack, bool deleteAfterSend = false );
|
||||
void enable_XOR_crypt( bool bEnable, unsigned char *initial_key );
|
||||
void notifySessionKeysOK();
|
||||
|
||||
protected:
|
||||
// signals to stop and waits for thread to stop
|
||||
bool stopThread();
|
||||
static DWORD WINAPI ClientThread( LPVOID lpvParam );
|
||||
|
||||
protected:
|
||||
// informational stings
|
||||
char m_ip[16];
|
||||
wchar_t m_wip[16];
|
||||
int m_port;
|
||||
wchar_t m_account[128];
|
||||
wchar_t m_tostring[128];
|
||||
// network-related vars
|
||||
SOCKET m_sock;
|
||||
bool m_was_force_disconnected;
|
||||
bool m_flagStop;
|
||||
bool m_isRunning;
|
||||
CriticalSection m_cs_send;
|
||||
ClientState m_state;
|
||||
bool m_xor_enabled;
|
||||
unsigned char m_xor_key_send[16];
|
||||
unsigned char m_xor_key_recv[16];
|
||||
ClientPacketHandler *m_ph;
|
||||
bool m_protocolIsOk;
|
||||
GameClientNetStats m_netStats;
|
||||
unsigned int m_opcodeObfuscationSeed;
|
||||
L2PCodeObfuscator *m_obf;
|
||||
unsigned char m_playKey[8];
|
||||
unsigned char m_loginKey[8];
|
||||
//
|
||||
GamePlayer *m_player;
|
||||
};
|
67
L2C_Server/net/GameClient/GameClientNet.cpp
Normal file
67
L2C_Server/net/GameClient/GameClientNet.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
#include "GS.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "utils/Exception.h"
|
||||
|
||||
bool GameClient::sendPacket( L2GamePacket *pack, bool deleteAfterSend /*= false*/ )
|
||||
{
|
||||
if( !pack ) return false;
|
||||
if( m_sock == INVALID_SOCKET ) return false;
|
||||
//
|
||||
int r = 0;
|
||||
unsigned int sentLen = 0;
|
||||
unsigned int pack_size = pack->getPacketSize();
|
||||
bool ret = true;
|
||||
// encode xor if xor enabled
|
||||
if( m_xor_enabled )
|
||||
{
|
||||
// KeyPacket is first packet sent to client by server.
|
||||
// it is never encrypted
|
||||
if( m_netStats.ullPacketsSent > 0 )
|
||||
pack->encodeXOR( m_xor_key_send );
|
||||
}
|
||||
// send packet (lock before send, release lock after send)
|
||||
m_cs_send.Lock();
|
||||
r = L2PacketSend( m_sock, pack, 2000, &sentLen );
|
||||
m_cs_send.Unlock();
|
||||
// delete pack, if set to do so
|
||||
if( deleteAfterSend ) delete pack;
|
||||
// validate send OK
|
||||
if( r<=0 || (sentLen != pack_size) ) // some error
|
||||
{
|
||||
ret = false;
|
||||
throw Exception( "%S: send error: sent %u, retval %d", toString(), sentLen, r );
|
||||
}
|
||||
// count stats
|
||||
m_netStats.addSentPacket( sentLen );
|
||||
//
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GameClient::enable_XOR_crypt( bool bEnable, unsigned char *initial_key )
|
||||
{
|
||||
m_xor_enabled = bEnable;
|
||||
if( bEnable )
|
||||
{
|
||||
memcpy( m_xor_key_recv, initial_key, sizeof(m_xor_key_recv) );
|
||||
memcpy( m_xor_key_send, initial_key, sizeof(m_xor_key_send) );
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( m_xor_key_recv, 0, sizeof(m_xor_key_recv) );
|
||||
memset( m_xor_key_send, 0, sizeof(m_xor_key_send) );
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::notifySessionKeysOK()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogDebug( L"GameClient::notifySessionKeysOK()" );
|
||||
#endif
|
||||
m_state = CLIENT_STATE_AUTHED;
|
||||
swprintf( m_tostring, 128, L"Client Acc: %s [IP %s:%d]", m_account, m_wip, m_port );
|
||||
sendPacket( ServerPackets::CharacterSelectionInfo( this ), true );
|
||||
}
|
25
L2C_Server/net/GameClient/GameClientNetStats.cpp
Normal file
25
L2C_Server/net/GameClient/GameClientNetStats.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "pch.h"
|
||||
#include "GameClientNetStats.h"
|
||||
|
||||
GameClientNetStats::GameClientNetStats()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void GameClientNetStats::clear()
|
||||
{
|
||||
ullPacketsSent = ullBytesSent = ullPacketsRcvd = ullBytesRcvd = 0;
|
||||
}
|
||||
|
||||
void GameClientNetStats::addSentPacket( unsigned long long len )
|
||||
{
|
||||
ullPacketsSent++;
|
||||
ullBytesSent += len;
|
||||
}
|
||||
|
||||
void GameClientNetStats::addRcvdPacket( unsigned long long len )
|
||||
{
|
||||
ullPacketsRcvd++;
|
||||
ullBytesRcvd += len;
|
||||
}
|
||||
|
15
L2C_Server/net/GameClient/GameClientNetStats.h
Normal file
15
L2C_Server/net/GameClient/GameClientNetStats.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
class GameClientNetStats
|
||||
{
|
||||
public:
|
||||
GameClientNetStats();
|
||||
void clear();
|
||||
void addSentPacket( unsigned long long len );
|
||||
void addRcvdPacket( unsigned long long len );
|
||||
public:
|
||||
unsigned long long ullPacketsSent;
|
||||
unsigned long long ullBytesSent;
|
||||
unsigned long long ullPacketsRcvd;
|
||||
unsigned long long ullBytesRcvd;
|
||||
};
|
188
L2C_Server/net/GameClient/GameClientThread.cpp
Normal file
188
L2C_Server/net/GameClient/GameClientThread.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
#include "GS.h"
|
||||
#include "utils/Exception.h"
|
||||
|
||||
bool GameClient::startThread()
|
||||
{
|
||||
if( m_isRunning ) return false;
|
||||
m_flagStop = false;
|
||||
unsigned int tid = 0;
|
||||
HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0,
|
||||
(unsigned int (__stdcall *)(void *))GameClient::ClientThread, (void *)this,
|
||||
0, &tid );
|
||||
bool ret = false;
|
||||
if( hThread != NULL )
|
||||
{
|
||||
ret = true;
|
||||
CloseHandle( hThread );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GameClient::stopThread()
|
||||
{
|
||||
if( !m_isRunning ) return false;
|
||||
m_flagStop = true;
|
||||
while( m_isRunning ) Sleep(50);
|
||||
m_flagStop = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameClient::disconnectForceAndWaitThreadToStop( bool server_shutdown, bool reasonDualLogin )
|
||||
{
|
||||
m_was_force_disconnected = true;
|
||||
// TODO: send SystemMessage about account in use if dual login
|
||||
if( reasonDualLogin )
|
||||
{
|
||||
}
|
||||
// TODO: send ServerClose / ExRestartClient? if server shutdown
|
||||
if( server_shutdown )
|
||||
{
|
||||
}
|
||||
stopThread(); // stops thread; thread cleanups socket himself
|
||||
}
|
||||
|
||||
void GameClient::signalThreadStop( bool setMarkToDeleteSelfAndCleanupClientPool )
|
||||
{
|
||||
m_flagStop = true;
|
||||
m_was_force_disconnected = !setMarkToDeleteSelfAndCleanupClientPool;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI GameClient::ClientThread( LPVOID lpvParam )
|
||||
{
|
||||
GameClient *pl = (GameClient *)lpvParam;
|
||||
pl->m_was_force_disconnected = false;
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
pl->m_isRunning = true;
|
||||
pl->m_state = CLIENT_STATE_CONNECTED;
|
||||
pl->m_netStats.clear(); // reset nework statistics
|
||||
|
||||
int r, bReadyRead, bReadyWrite;
|
||||
unsigned char *packbuffer = NULL;
|
||||
unsigned int rcvdLen = 0;
|
||||
L2GamePacket *pack = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// allocate packets recv buffer
|
||||
packbuffer = (unsigned char *)malloc( 65536 );
|
||||
if( !packbuffer ) throw std::bad_alloc( "allocate packbuffer (64 Kb) failed" );
|
||||
|
||||
// packets recv loop
|
||||
while( !pl->m_flagStop )
|
||||
{
|
||||
// wait for socket ready to receive data
|
||||
r = L2PNet_select( pl->m_sock, L2PNET_SELECT_READ, 100, &bReadyRead, &bReadyWrite );
|
||||
if( r == 0 )
|
||||
{
|
||||
// select timout
|
||||
// update world state? move moving objects?...
|
||||
continue;
|
||||
}
|
||||
if( r == -1 ) // select error
|
||||
{
|
||||
LogError( L"%s: L2PNet_select() error!", pl->toString() );
|
||||
throw Exception( "select error" );
|
||||
}
|
||||
|
||||
// recv packet
|
||||
r = L2PacketReceive_buffer( pl->m_sock, 1000, &rcvdLen, packbuffer );
|
||||
if( r <= 0 )
|
||||
{
|
||||
if( r == 0 )
|
||||
{
|
||||
LogWarning( L"%s: closed connection? (received %u, retval %d)", pl->toString(), rcvdLen, r );
|
||||
pl->m_flagStop = true;
|
||||
break;
|
||||
}
|
||||
if( r < 0 )
|
||||
{
|
||||
LogError( L"%s: failed to receive packet (received %u, retval %d)", pl->toString(), rcvdLen, r );
|
||||
throw Exception( "network packet receive error" );
|
||||
}
|
||||
}
|
||||
|
||||
// count stats
|
||||
pl->m_netStats.addRcvdPacket( rcvdLen );
|
||||
|
||||
// create packet object
|
||||
pack = new L2GamePacket( packbuffer, rcvdLen );
|
||||
|
||||
// decode XOR if enabled
|
||||
if( pl->m_xor_enabled ) pack->decodeXOR( pl->m_xor_key_recv );
|
||||
|
||||
// deobfuscate opcode if enabled
|
||||
if( pl->m_opcodeObfuscationSeed > 0 )
|
||||
{
|
||||
// HACK: here buffer that should be constant, is modified (but length is not changed thoug)
|
||||
pl->m_obf->decodeIDs( (unsigned char *)pack->getBytesPtr() );
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
int opcode = pack->getByteAt(2);
|
||||
LogDebug( L"%s: opcode %02X", pl->toString(), opcode );
|
||||
#endif
|
||||
|
||||
// handle game client packet...
|
||||
pl->m_ph->handlePacket( pack );
|
||||
|
||||
// free packet object
|
||||
delete pack; pack = NULL;
|
||||
}
|
||||
}
|
||||
catch( L2P_Exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: L2Packets exception: %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( std::bad_alloc& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: bad_alloc %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: std::excpt %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
|
||||
// player disconnected - remove player account from login server list of authed accounts
|
||||
if( pl->m_account[0] ) // has authed??
|
||||
gs->logoutAccountFromLoginServer( pl->m_account );
|
||||
|
||||
// cleanup socket
|
||||
L2PNet_shutdown( pl->m_sock );
|
||||
L2PNet_closesocket( pl->m_sock );
|
||||
pl->m_sock = INVALID_SOCKET;
|
||||
pl->m_state = CLIENT_STATE_OFFLINE;
|
||||
// cleanup opcode obfuscator
|
||||
if( pl->m_obf )
|
||||
{
|
||||
delete pl->m_obf;
|
||||
pl->m_obf = NULL;
|
||||
pl->m_opcodeObfuscationSeed = 0;
|
||||
}
|
||||
|
||||
// free packets buffer
|
||||
if( packbuffer ) free( packbuffer ); packbuffer = NULL;
|
||||
|
||||
// mark self as finished
|
||||
pl->m_isRunning = false;
|
||||
|
||||
// notify GS ClientPool about client stop, if needed
|
||||
if( !pl->m_was_force_disconnected )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogDebug( L"ClientThread s: Calling ClientPool to cleanup & deleting self", pl->toString() );
|
||||
#endif
|
||||
gs->getClientPool()->notifyClientThreadEnded( pl );
|
||||
delete pl;
|
||||
}
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user