2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
# include <StdAfx.h>
2018-03-29 17:01:57 -04:00
# include "Network.h"
# include "Client.h"
# include "ClientEvents.h"
# include "World.h"
2019-07-07 20:56:15 +00:00
# include "crc.h"
2018-03-29 17:01:57 -04:00
# include "BinaryWriter.h"
# include "BinaryReader.h"
# include "PacketController.h"
# include "Server.h"
# include "Config.h"
2020-06-06 23:22:18 +00:00
# include "SHA512.h"
2018-03-29 17:01:57 -04:00
// NOTE: A client can easily perform denial of service attacks by issuing a large number of connection requests if there ever comes a time this matters to fix
2018-08-15 21:29:07 -05:00
CNetwork : : CNetwork ( class CPhatServer * server , in_addr address , WORD port )
2018-03-29 17:01:57 -04:00
{
m_server = server ;
2018-08-15 21:29:07 -05:00
m_port = port ;
m_addr = address ;
2018-03-29 17:01:57 -04:00
m_ServerID = 11 ; // arbitrary
LoadBans ( ) ;
2018-08-15 21:29:07 -05:00
Init ( ) ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
m_running = true ;
m_incomingThread = std : : thread ( [ & ] ( ) { IncomingThreadProc ( ) ; } ) ;
m_outgoingThread = std : : thread ( [ & ] ( ) { OutgoingThreadProc ( ) ; } ) ;
2018-03-29 17:01:57 -04:00
}
CNetwork : : ~ CNetwork ( )
{
2018-08-15 21:29:07 -05:00
m_running = false ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
if ( m_outgoingThread . joinable ( ) )
m_outgoingThread . join ( ) ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
if ( m_incomingThread . joinable ( ) )
m_incomingThread . join ( ) ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
Shutdown ( ) ;
2018-03-29 17:01:57 -04:00
_queuedIncoming . clear ( ) ;
_queuedOutgoing . clear ( ) ;
}
void CNetwork : : Init ( )
{
2018-08-15 21:29:07 -05:00
srand ( ( unsigned int ) time ( NULL ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
xsocket : : socket_init ( ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
WINLOG ( Temp , Normal , " Binding to addr %s \n " , inet_ntoa ( m_addr ) ) ;
if ( m_read_sock . bind ( m_addr , m_port ) )
2018-08-15 21:29:07 -05:00
{
WINLOG ( Temp , Normal , " Failed bind on recv port %u! \n " , m_port ) ;
2019-07-07 20:56:15 +00:00
SERVER_ERROR < < " Failed bind on recv port: " < < m_port ;
2018-08-15 21:29:07 -05:00
}
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
if ( m_write_sock . bind ( m_addr , m_port + 1 ) )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
WINLOG ( Temp , Normal , " Failed bind on send port %u! \n " , m_port + 1 ) ;
SERVER_ERROR < < " Failed bind on send port: " < < m_port + 1 ;
2018-08-15 21:29:07 -05:00
}
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
// configure for non-blocking
2019-04-26 11:23:38 -05:00
int buffsize = g_pConfig - > NetBufferSize ( ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
m_read_sock . blocking ( false ) ;
m_read_sock . buffer_size ( & buffsize , & buffsize ) ;
m_write_sock . blocking ( false ) ;
m_write_sock . buffer_size ( & buffsize , & buffsize ) ;
2018-08-15 21:29:07 -05:00
}
void CNetwork : : Shutdown ( )
{
2020-06-06 23:22:18 +00:00
SaveBans ( ) ;
2019-07-07 20:56:15 +00:00
m_read_sock . close ( ) ;
m_write_sock . close ( ) ;
xsocket : : socket_shutdown ( ) ;
2018-08-15 21:29:07 -05:00
}
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
void CNetwork : : IncomingThreadProc ( )
{
2019-07-07 20:56:15 +00:00
xsocket : : socket_wait wait ;
2018-08-18 20:42:30 -05:00
2018-08-15 21:29:07 -05:00
while ( m_running )
{
2019-07-07 20:56:15 +00:00
wait . reset ( ) ;
wait . set ( m_read_sock ) ;
wait . set ( m_write_sock ) ;
2018-08-18 20:42:30 -05:00
2019-07-07 20:56:15 +00:00
int result = wait . wait ( ) ;
2018-08-28 01:51:42 -05:00
2019-07-07 20:56:15 +00:00
if ( result > 0 )
{
if ( wait . isset ( m_read_sock ) )
QueueIncomingOnSocket ( m_read_sock ) ;
if ( wait . isset ( m_write_sock ) )
QueueIncomingOnSocket ( m_write_sock ) ;
}
2018-08-15 21:29:07 -05:00
std : : this_thread : : yield ( ) ;
}
}
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
void CNetwork : : OutgoingThreadProc ( )
{
while ( m_running )
{
2018-08-18 20:42:30 -05:00
{
std : : unique_lock sigLock ( m_sigOutgoingLock ) ;
m_sigOutgoing . wait_for ( sigLock , std : : chrono : : seconds ( 1 ) ) ;
}
while ( ! _queuedOutgoing . empty ( ) )
2018-08-15 21:29:07 -05:00
{
std : : scoped_lock lock ( m_outgoingLock ) ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
auto entry = _queuedOutgoing . begin ( ) ;
if ( entry ! = _queuedOutgoing . end ( ) )
{
2018-08-16 12:48:45 -05:00
CQueuedPacket & queued = * entry ;
2018-08-22 22:31:27 -05:00
//if (SendPacket(queued.useReadStream ? m_read_sock : m_write_sock, &queued.addr, queued.data.get(), queued.len))
2020-07-07 13:39:25 -07:00
SendPacket ( queued . useReadStream ? m_read_sock : m_read_sock , & queued . addr , queued . data . get ( ) , queued . len ) ;
_queuedOutgoing . erase ( entry ) ;
2018-08-18 20:42:30 -05:00
std : : this_thread : : yield ( ) ;
2018-08-15 21:29:07 -05:00
}
}
std : : this_thread : : yield ( ) ;
}
2018-03-29 17:01:57 -04:00
}
WORD CNetwork : : GetServerID ( void )
{
return m_ServerID ;
}
2019-07-07 20:56:15 +00:00
void CNetwork : : SendConnectlessBlob ( SOCKADDR_IN * peer , BlobPacket_s * blob , uint32_t dwFlags , uint32_t dwSequence , WORD wTime , bool useReadStream )
2018-03-29 17:01:57 -04:00
{
BlobHeader_s * header = & blob - > header ;
header - > dwSequence = dwSequence ;
header - > dwFlags = dwFlags ;
header - > dwCRC = 0 ;
header - > wRecID = GetServerID ( ) ;
header - > wTime = wTime ;
header - > wTable = 0x01 ;
GenericCRC ( blob ) ;
2018-08-15 21:29:07 -05:00
QueuePacket ( peer , blob , BLOBLEN ( blob ) , useReadStream ) ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
bool CNetwork : : SendPacket ( xsocket : : socket_udp socket , sockaddr_in * peer , void * data , uint32_t len )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
if ( ! socket . valid ( ) )
2018-03-29 17:01:57 -04:00
{
2020-08-08 04:48:54 +00:00
NETWORK_LOG < < " Invalid socket: " < < inet_ntoa ( peer - > sin_addr ) < < " : " < < peer - > sin_port ;
2018-03-29 17:01:57 -04:00
return false ;
}
2018-08-19 09:37:41 -05:00
//WINLOG(Temp, Normal, "Sending to %s:%d\n", inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));
2019-07-07 20:56:15 +00:00
int bytesSent = socket . sendto ( ( uint8_t * ) data , len , peer ) ;
2018-08-19 09:37:41 -05:00
2019-07-07 20:56:15 +00:00
bool success = ( bytesSent > 0 ) ;
2018-03-29 17:01:57 -04:00
if ( success )
{
/*
# ifdef _DEBUG
if ( false ) // g_bDebugToggle)
{
LOG ( Network , Normal , " Sent: \n " ) ;
LOG_BYTES ( Network , Normal , data , len ) ;
}
else
{
LOG ( Network , Verbose , " Sent to %s: \n " , inet_ntoa ( peer - > sin_addr ) ) ;
LOG_BYTES ( Network , Verbose , data , len ) ;
}
# endif
g_pGlobals - > PacketSent ( len ) ;
*/
}
2020-07-07 13:39:25 -07:00
else
{
2020-08-08 04:48:54 +00:00
NETWORK_LOG < < " Failed send: " < < inet_ntoa ( peer - > sin_addr ) < < " : " < < peer - > sin_port < < " - " < < bytesSent < < " bytes sent " < < " - " < < xsocket : : socket_error_text ( xsocket : : socket_error ( ) ) ;
2020-07-07 13:39:25 -07:00
}
2018-03-29 17:01:57 -04:00
return success ;
}
2019-07-07 20:56:15 +00:00
void CNetwork : : QueuePacket ( SOCKADDR_IN * peer , void * data , uint32_t len , bool useReadStream )
2018-03-29 17:01:57 -04:00
{
CQueuedPacket qp ;
qp . addr = * peer ;
2018-08-16 12:48:45 -05:00
qp . data = std : : make_unique < BYTE [ ] > ( len ) ;
memcpy ( qp . data . get ( ) , data , len ) ;
2018-03-29 17:01:57 -04:00
qp . len = len ;
2018-08-15 21:29:07 -05:00
qp . useReadStream = useReadStream ;
2018-03-29 17:01:57 -04:00
{
2018-08-16 12:48:45 -05:00
std : : scoped_lock lock ( m_outgoingLock ) ;
_queuedOutgoing . push_back ( std : : move ( qp ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-08-18 20:42:30 -05:00
m_sigOutgoing . notify_all ( ) ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
void CNetwork : : QueueIncomingOnSocket ( xsocket : : socket_udp socket )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
if ( ! socket . valid ( ) )
2018-03-29 17:01:57 -04:00
{
return ;
}
static BYTE buffer [ 0x1E4 ] ;
while ( TRUE )
{
int clientaddrlen = sizeof ( sockaddr_in ) ;
sockaddr_in clientaddr ;
// Doing it similar to AC..
2019-07-07 20:56:15 +00:00
int bloblen = socket . recvfrom ( buffer , sizeof ( buffer ) , & clientaddr ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
if ( bloblen < = 0 )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
// uint32_t dwCode = WSAGetLastError();
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
// if (dwCode != 10035)
// {
// // LOG(Temp, Normal, "Winsock Error %lu\n", dwCode);
// }
2018-03-29 17:01:57 -04:00
break ;
}
else if ( ! bloblen )
{
break ;
}
else if ( bloblen < sizeof ( BlobHeader_s ) )
{
continue ;
}
g_pGlobals - > PacketRecv ( bloblen ) ;
BlobPacket_s * blob = reinterpret_cast < BlobPacket_s * > ( buffer ) ;
WORD wSize = blob - > header . wSize ;
WORD wRecID = blob - > header . wRecID ;
if ( ( bloblen - sizeof ( BlobHeader_s ) ) ! = wSize )
continue ;
2020-06-06 23:22:18 +00:00
if ( wRecID = = 0 )
{
ProcessConnectionless ( & clientaddr , blob ) ;
continue ;
}
2018-03-29 17:01:57 -04:00
CQueuedPacket qp ;
memcpy ( & qp . addr , & clientaddr , sizeof ( sockaddr_in ) ) ;
2018-08-16 12:48:45 -05:00
qp . data = std : : make_unique < BYTE [ ] > ( bloblen ) ;
memcpy ( qp . data . get ( ) , buffer , bloblen ) ;
2018-03-29 17:01:57 -04:00
qp . len = bloblen ;
2020-06-06 23:22:18 +00:00
qp . recvTime = g_pGlobals - > Time ( ) ;
2018-03-29 17:01:57 -04:00
2018-08-15 21:29:07 -05:00
{
std : : scoped_lock lock ( m_incomingLock ) ;
2018-08-16 12:48:45 -05:00
_queuedIncoming . push_back ( std : : move ( qp ) ) ;
2018-08-15 21:29:07 -05:00
}
2018-03-29 17:01:57 -04:00
/*
# ifdef _DEBUG
SOCKADDR_IN addr ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
int namelen = sizeof ( addr ) ;
getsockname ( socket , ( sockaddr * ) & addr , & namelen ) ;
if ( false ) // g_bDebugToggle)
{
LOG ( Network , Normal , " Received on port %d: \n " , ntohs ( addr . sin_port ) ) ;
LOG_BYTES ( Network , Normal , & blob - > header , blob - > header . wSize + sizeof ( blob - > header ) ) ;
}
else
{
LOG ( Network , Verbose , " Received on port %d: \n " , ntohs ( addr . sin_port ) ) ;
LOG_BYTES ( Network , Verbose , & blob - > header , blob - > header . wSize + sizeof ( blob - > header ) ) ;
}
# endif
*/
}
}
void CNetwork : : ProcessQueuedIncoming ( )
{
2018-08-16 12:48:45 -05:00
while ( ! _queuedIncoming . empty ( ) )
2018-03-29 17:01:57 -04:00
{
2018-08-16 12:48:45 -05:00
CQueuedPacket qp ;
2018-03-29 17:01:57 -04:00
{
2018-08-15 21:29:07 -05:00
std : : scoped_lock lock ( m_incomingLock ) ;
2018-08-16 12:48:45 -05:00
qp = std : : move ( _queuedIncoming . front ( ) ) ;
2018-03-29 17:01:57 -04:00
_queuedIncoming . pop_front ( ) ;
}
2018-08-16 12:48:45 -05:00
BlobPacket_s * blob = ( BlobPacket_s * ) qp . data . get ( ) ;
2019-07-07 20:56:15 +00:00
blob - > header . dwCRC - = CalcTransportCRC ( ( uint32_t * ) blob ) ;
2018-03-29 17:01:57 -04:00
2018-08-16 12:48:45 -05:00
if ( ! blob - > header . wRecID )
2018-03-29 17:01:57 -04:00
{
2018-08-16 12:48:45 -05:00
ProcessConnectionless ( & qp . addr , blob ) ;
2018-03-29 17:01:57 -04:00
}
2018-08-16 12:48:45 -05:00
else if ( CClient * client = ValidateClient ( blob - > header . wRecID , & qp . addr ) )
{
client - > IncomingBlob ( blob , qp . recvTime ) ;
}
}
2018-03-29 17:01:57 -04:00
}
void CNetwork : : LogoutAll ( )
{
2020-06-06 23:22:18 +00:00
for ( auto entry : m_clients )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
CClient * client = entry . second ;
if ( client & & client - > IsAlive ( ) & & client - > GetEvents ( ) )
client - > GetEvents ( ) - > ForceLogout ( ) ;
2018-03-29 17:01:57 -04:00
}
}
void CNetwork : : CompleteLogoutAll ( )
{
2020-06-06 23:22:18 +00:00
for ( auto entry : m_clients )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
CClient * client = entry . second ;
if ( client & & client - > IsAlive ( ) & & client - > GetEvents ( ) )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
BinaryWriter EnterPortal ;
EnterPortal . Write < uint32_t > ( 0xF751 ) ;
EnterPortal . Write < uint32_t > ( 0 ) ;
client - > SendNetMessage ( EnterPortal . GetData ( ) , EnterPortal . GetSize ( ) , OBJECT_MSG ) ;
BinaryWriter popupString ;
popupString . Write < uint32_t > ( 4 ) ;
popupString . WriteString ( " The server has shutdown. " ) ;
client - > SendNetMessage ( & popupString , PRIVATE_MSG , FALSE , FALSE ) ;
2018-03-29 17:01:57 -04:00
}
}
}
void CNetwork : : Think ( )
{
ProcessQueuedIncoming ( ) ;
2020-06-06 23:22:18 +00:00
auto itr = m_clients . begin ( ) ;
while ( itr ! = m_clients . end ( ) )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
CClient * client = itr - > second ;
if ( ! client | | ! client - > IsAlive ( ) )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
// nuke it
SERVER_INFO < < " Client " < < client - > GetAccount ( ) < < " ( " < < inet_ntoa ( client - > GetHostAddress ( ) - > sin_addr ) < < " ) disconnected " ;
delete client ;
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
std : : scoped_lock lock ( m_clientsLock ) ;
itr = m_clients . erase ( itr ) ;
2018-03-29 17:01:57 -04:00
}
2020-06-06 23:22:18 +00:00
continue ;
2018-03-29 17:01:57 -04:00
}
2020-06-06 23:22:18 +00:00
client - > Think ( ) ;
itr + + ;
2018-03-29 17:01:57 -04:00
}
2019-02-07 00:17:17 -06:00
2020-04-30 16:58:53 +00:00
# if defined(__cpp_lib_execution) && defined(__cpp_lib_parallel_algorithm)
2020-06-06 23:22:18 +00:00
std : : for_each ( std : : execution : : par , m_clients . begin ( ) , m_clients . end ( ) , [ ] ( client_list_value_t & client )
2019-07-07 20:56:15 +00:00
# else
2020-06-06 23:22:18 +00:00
std : : for_each ( m_clients . begin ( ) , m_clients . end ( ) , [ ] ( client_list_value_t & client )
2019-07-07 20:56:15 +00:00
# endif
2019-02-07 00:17:17 -06:00
{
2020-06-06 23:22:18 +00:00
client . second - > ThinkOutbound ( ) ;
2019-02-07 00:17:17 -06:00
} ) ;
2020-06-06 23:22:18 +00:00
if ( m_lastBanSave + 30.0 < g_pGlobals - > Time ( ) )
{
SaveBans ( ) ;
m_lastBanSave = g_pGlobals - > Time ( ) ;
}
2018-03-29 17:01:57 -04:00
}
CClient * CNetwork : : GetClient ( WORD slot )
{
2020-06-06 23:22:18 +00:00
auto itr = m_clients . find ( slot ) ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( itr ! = m_clients . end ( ) )
{
return itr - > second ;
}
return nullptr ;
2018-03-29 17:01:57 -04:00
}
void CNetwork : : KickClient ( CClient * pClient )
{
if ( ! pClient )
return ;
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Client " < < pClient - > GetSlot ( ) < < " ( " < < pClient - > GetAccount ( ) < < " ) is being kicked. " ;
2018-03-29 17:01:57 -04:00
BinaryWriter KC ;
2019-07-07 20:56:15 +00:00
KC . Write < int32_t > ( 0xF7DC ) ;
KC . Write < int32_t > ( 0 ) ;
2018-03-29 17:01:57 -04:00
pClient - > SendNetMessage ( KC . GetData ( ) , KC . GetSize ( ) , PRIVATE_MSG ) ;
pClient - > ThinkOutbound ( ) ;
pClient - > Kill ( NULL , NULL ) ;
}
2019-07-07 20:56:15 +00:00
void CNetwork : : KickBannedClient ( CClient * pClient , int32_t duration )
2019-01-25 02:26:45 -06:00
{
if ( ! pClient )
return ;
// newlines to push turbine support url out of the window.
std : : string msg ;
msg + = " \n \n " ;
msg + = g_pConfig - > GetBanString ( ) ;
msg + = " \n \n \n \n " ;
BinaryWriter KBC ;
2019-07-07 20:56:15 +00:00
KBC . Write < int32_t > ( 0xF7C1 ) ;
KBC . Write < int32_t > ( duration ) ; // ban duration in seconds
2019-01-25 02:26:45 -06:00
KBC . WriteString ( msg ) ;
pClient - > SendNetMessage ( KBC . GetData ( ) , KBC . GetSize ( ) , PRIVATE_MSG ) ;
pClient - > ThinkOutbound ( ) ;
pClient - > Kill ( NULL , NULL ) ;
}
2018-03-29 17:01:57 -04:00
void CNetwork : : KickClient ( WORD slot )
{
KickClient ( GetClient ( slot ) ) ;
}
CClient * CNetwork : : ValidateClient ( WORD index , sockaddr_in * peer )
{
CClient * pClient = GetClient ( index ) ;
if ( ! pClient )
return NULL ;
if ( ! pClient - > CheckAddress ( peer ) )
return NULL ;
return pClient ;
}
void CNetwork : : KillClient ( WORD slot )
{
2020-06-06 23:22:18 +00:00
//if (CClient *pClient = GetClient(slot))
//{
// SERVER_INFO << "Client" << pClient->GetAccount() << "(" << inet_ntoa(pClient->GetHostAddress()->sin_addr) << ") disconnected";
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// uint32_t arrayPos = pClient->GetArrayPos();
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// delete pClient;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// m_NumClients--;
// m_ClientArray[arrayPos] = m_ClientArray[m_NumClients];
// m_ClientArray[m_NumClients] = NULL;
// m_ClientSlots[slot] = NULL;
// m_OpenSlots.push_front(slot);
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// if (m_ClientArray[arrayPos])
// {
// m_ClientArray[arrayPos]->SetArrayPos(arrayPos);
// }
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// // m_server->Stats().UpdateClientList(NULL, 0);
//}
2018-03-29 17:01:57 -04:00
}
CClient * CNetwork : : FindClientByAccount ( const char * account )
{
2020-06-06 23:22:18 +00:00
for ( auto entry : m_clients )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
if ( entry . second & & entry . second - > CheckAccount ( account ) )
return entry . second ;
2018-03-29 17:01:57 -04:00
}
2020-06-06 23:22:18 +00:00
return nullptr ;
2018-03-29 17:01:57 -04:00
}
void CNetwork : : SendConnectLoginFailure ( sockaddr_in * addr , int error , const char * accountname , const char * password )
{
//Bad login.
2019-04-13 18:18:28 +00:00
CREATEBLOB ( BadLogin , sizeof ( uint32_t ) * 2 ) ;
( ( uint32_t * ) BadLogin - > data ) [ 0 ] = ( uint32_t ) error ;
( ( uint32_t * ) BadLogin - > data ) [ 1 ] = ST_SERVER_ERRORS ;
2018-03-29 17:01:57 -04:00
2019-04-13 18:18:28 +00:00
SendConnectlessBlob ( addr , BadLogin , BT_NETERROR , 0 , 0 , true ) ;
//SendConnectlessBlob(addr, BadLogin, BT_ERROR, 0, 0, true);
2018-03-29 17:01:57 -04:00
DELETEBLOB ( BadLogin ) ;
2019-04-13 18:18:28 +00:00
if ( accountname )
2018-03-29 17:01:57 -04:00
{
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Invalid login from " < < inet_ntoa ( addr - > sin_addr ) < < " , used account name ' " < < accountname < < " ' " ;
2018-03-29 17:01:57 -04:00
}
}
void CNetwork : : ConnectionRequest ( sockaddr_in * addr , BlobPacket_s * p )
{
2020-06-06 23:22:18 +00:00
g_pDB2 - > QueueAsyncQuery ( new AuthenticateUserQuery ( * addr , p ) ) ;
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
void CNetwork : : ProcessConnectionless ( sockaddr_in * peer , BlobPacket_s * blob )
{
uint32_t dwFlags = blob - > header . dwFlags ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( dwFlags = = BT_LOGIN )
{
ConnectionRequest ( peer , blob ) ;
2018-03-29 17:01:57 -04:00
return ;
2020-06-06 23:22:18 +00:00
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// LOG(Network, Verbose, "Unhandled connectionless packet received: 0x%08X Look into this\n", dwFlags);
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
void CNetwork : : AcceptClientLogin ( sockaddr_in * addr , AccountInformation_t account , uint32_t timestamp , uint32_t portal_stamp , uint32_t cell_stamp )
{
// this isn't happening on the same threads as before
// make sure everything is protected
CClient * client = FindClientByAccount ( account . username . c_str ( ) ) ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( client )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
if ( stricmp ( client - > GetAccount ( ) , " admin " ) )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_ACCOUNT_ONLINE , nullptr , nullptr ) ;
return ;
2018-03-29 17:01:57 -04:00
}
else
{
2020-06-06 23:22:18 +00:00
// TODO: make sure this client is using the same connection, otherwise send an error
2018-03-29 17:01:57 -04:00
return ;
}
}
2020-06-06 23:22:18 +00:00
if ( isFull ( ) )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
if ( account . access = = 5 )
2018-03-29 17:01:57 -04:00
{
2020-06-06 23:22:18 +00:00
// setup to allow admins access
2018-03-29 17:01:57 -04:00
}
else
{
2020-06-06 23:22:18 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_SERVER_FULL , nullptr , nullptr ) ;
2018-03-29 17:01:57 -04:00
return ;
}
}
2020-06-06 23:22:18 +00:00
uint16_t slot = GetClientId ( ) ;
2019-04-13 18:18:28 +00:00
2020-06-06 23:22:18 +00:00
SERVER_INFO < < " Client " < < account . username < < " ( " < < inet_ntoa ( addr - > sin_addr ) < < " : " < < ntohs ( addr - > sin_port ) < < " ) connected on slot " < < slot ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
client = new CClient ( addr , slot , account ) ;
client - > SetLoginData ( timestamp , portal_stamp , cell_stamp ) ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
{
std : : scoped_lock lock ( m_clientsLock ) ;
m_clients . insert ( { slot , client } ) ;
2018-03-29 17:01:57 -04:00
}
// Add the client to the HUD
// m_server->Stats().UpdateClientList(m_clients, m_slotrange);
BinaryWriter AcceptConnect ;
// Some server variables
AcceptConnect . Write < double > ( g_pGlobals - > Time ( ) ) ;
BYTE cookie [ ] = {
0xbe , 0xc8 , 0x8a , 0x58 , 0x0b , 0x1e , 0x99 , 0x43
} ;
AcceptConnect . Write ( cookie , sizeof ( cookie ) ) ;
2019-07-07 20:56:15 +00:00
AcceptConnect . Write < uint32_t > ( slot ) ;
AcceptConnect . Write < uint32_t > ( client - > GetPacketController ( ) - > GetServerCryptoSeed ( ) ) ;
AcceptConnect . Write < uint32_t > ( client - > GetPacketController ( ) - > GetClientCryptoSeed ( ) ) ;
AcceptConnect . Write < uint32_t > ( 2 ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t dwLength = AcceptConnect . GetSize ( ) ;
2018-03-29 17:01:57 -04:00
if ( dwLength < = 0x1D0 )
{
CREATEBLOB ( Woot , ( WORD ) dwLength ) ;
memcpy ( Woot - > data , AcceptConnect . GetData ( ) , dwLength ) ;
2018-08-20 21:11:46 -05:00
SendConnectlessBlob ( addr , Woot , BT_LOGINREPLY , 0x00000000 , 0 , true ) ;
2018-03-29 17:01:57 -04:00
DELETEBLOB ( Woot ) ;
2019-01-25 02:26:45 -06:00
// Check the account in the database to prevent users from changing their ip
2020-06-06 23:22:18 +00:00
if ( IsBannedIP ( addr - > sin_addr ) | | account . banned = = true )
2019-01-25 02:26:45 -06:00
{
2019-07-07 20:56:15 +00:00
int32_t duration = GetBanDuration ( addr - > sin_addr ) ;
2019-01-25 02:26:45 -06:00
if ( duration > = 0 )
KickBannedClient ( client , duration ) ;
else
{
RemoveBan ( addr - > sin_addr ) ;
2020-06-06 23:22:18 +00:00
g_pDBIO - > UpdateBan ( account . id , false ) ;
2019-01-25 02:26:45 -06:00
}
return ;
}
2018-03-29 17:01:57 -04:00
}
else
{
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " AcceptConnect.GetSize() > 0x1D0 " ;
2018-03-29 17:01:57 -04:00
}
}
DEFINE_PACK ( CBanDescription )
{
2019-07-07 20:56:15 +00:00
pWriter - > Write < uint32_t > ( 2 ) ; // version
2018-03-29 17:01:57 -04:00
pWriter - > WriteString ( m_AdminName ) ;
pWriter - > WriteString ( m_Reason ) ;
2019-07-07 20:56:15 +00:00
pWriter - > Write < uint32_t > ( m_Timestamp ) ;
pWriter - > Write < int32_t > ( m_BanDuration ) ;
pWriter - > Write < uint32_t > ( m_AccountID ) ;
2018-03-29 17:01:57 -04:00
}
DEFINE_UNPACK ( CBanDescription )
{
2019-07-07 20:56:15 +00:00
uint32_t version = pReader - > Read < uint32_t > ( ) ;
2018-03-29 17:01:57 -04:00
m_AdminName = pReader - > ReadString ( ) ;
m_Reason = pReader - > ReadString ( ) ;
2019-07-07 20:56:15 +00:00
m_Timestamp = pReader - > Read < uint32_t > ( ) ;
2019-01-25 02:26:45 -06:00
if ( version > 1 )
{
2019-07-07 20:56:15 +00:00
m_BanDuration = pReader - > Read < int32_t > ( ) ;
m_AccountID = pReader - > Read < uint32_t > ( ) ;
2019-01-25 02:26:45 -06:00
}
2018-03-29 17:01:57 -04:00
return true ;
}
DEFINE_PACK ( CNetworkBanList )
{
2019-07-07 20:56:15 +00:00
pWriter - > Write < uint32_t > ( 1 ) ; // version
2018-03-29 17:01:57 -04:00
m_BanTable . Pack ( pWriter ) ;
}
DEFINE_UNPACK ( CNetworkBanList )
{
m_BanTable . clear ( ) ;
2019-07-07 20:56:15 +00:00
uint32_t version = pReader - > Read < uint32_t > ( ) ;
2018-03-29 17:01:57 -04:00
m_BanTable . UnPack ( pReader ) ;
return true ;
}
bool CNetwork : : IsBannedIP ( in_addr ipaddr )
{
return m_Bans . m_BanTable . lookup ( ipaddr . s_addr ) ? true : false ;
}
2019-07-07 20:56:15 +00:00
int32_t CNetwork : : GetBanDuration ( in_addr ipaddr )
2019-01-25 02:26:45 -06:00
{
2019-05-09 04:39:36 +00:00
CBanDescription * ban = m_Bans . m_BanTable . lookup ( ipaddr . s_addr ) ;
2019-07-07 20:56:15 +00:00
int32_t timestamp , duration = 0 ;
2019-05-09 04:39:36 +00:00
if ( ban )
{
timestamp = ban - > m_Timestamp ;
duration = ban - > m_BanDuration ;
}
2019-01-25 02:26:45 -06:00
if ( ! duration )
return 0 ;
return ( timestamp + duration ) - time ( 0 ) ;
}
2019-07-07 20:56:15 +00:00
uint32_t CNetwork : : GetBanID ( in_addr ipaddr )
2019-01-25 02:26:45 -06:00
{
2019-07-07 20:56:15 +00:00
uint32_t id = m_Bans . m_BanTable . lookup ( ipaddr . s_addr ) - > m_AccountID ;
2019-01-25 02:26:45 -06:00
if ( ! id )
return 0 ;
return id ;
}
2018-03-29 17:01:57 -04:00
void CNetwork : : LoadBans ( )
{
void * data = NULL ;
2019-07-07 20:56:15 +00:00
unsigned long length = 0 ;
2018-03-29 17:01:57 -04:00
if ( g_pDBIO - > GetGlobalData ( DBIO_GLOBAL_BAN_DATA , & data , & length ) )
{
BinaryReader reader ( data , length ) ;
m_Bans . UnPack ( & reader ) ;
}
}
void CNetwork : : SaveBans ( )
{
BinaryWriter banData ;
m_Bans . Pack ( & banData ) ;
g_pDBIO - > CreateOrUpdateGlobalData ( DBIO_GLOBAL_BAN_DATA , banData . GetData ( ) , banData . GetSize ( ) ) ;
}
2019-07-07 20:56:15 +00:00
void CNetwork : : AddBan ( in_addr ipaddr , const char * admin , const char * reason , uint32_t account_id )
2019-01-25 02:26:45 -06:00
{
CBanDescription * pBan = & m_Bans . m_BanTable [ ipaddr . s_addr ] ;
pBan - > m_AdminName = admin ;
pBan - > m_Reason = reason ;
pBan - > m_Timestamp = time ( 0 ) ;
pBan - > m_BanDuration = 0 ;
pBan - > m_AccountID = account_id ;
}
2019-07-07 20:56:15 +00:00
void CNetwork : : AddBan ( in_addr ipaddr , const char * admin , const char * reason , int32_t duration , uint32_t account_id )
2018-03-29 17:01:57 -04:00
{
CBanDescription * pBan = & m_Bans . m_BanTable [ ipaddr . s_addr ] ;
pBan - > m_AdminName = admin ;
pBan - > m_Reason = reason ;
pBan - > m_Timestamp = time ( 0 ) ;
2019-01-25 02:26:45 -06:00
pBan - > m_BanDuration = duration ;
pBan - > m_AccountID = account_id ;
2018-03-29 17:01:57 -04:00
}
bool CNetwork : : RemoveBan ( in_addr ipaddr )
{
if ( m_Bans . m_BanTable . lookup ( ipaddr . s_addr ) )
{
m_Bans . m_BanTable . erase ( ipaddr . s_addr ) ;
return true ;
}
return false ;
}
std : : string CNetwork : : GetBanList ( )
{
std : : string banList = csprintf ( " Ban List (%d entries): " , m_Bans . m_BanTable . size ( ) ) ;
for ( auto & entry : m_Bans . m_BanTable )
{
CBanDescription * pBan = & entry . second ;
2019-01-25 02:26:45 -06:00
banList + = csprintf ( " \n %s - Admin: %s @ %s Reason: %s Duration: %d \n " , inet_ntoa ( * ( in_addr * ) & entry . first ) , pBan - > m_AdminName . c_str ( ) , timestampDateString ( pBan - > m_Timestamp ) , pBan - > m_Reason . c_str ( ) , GetBanDuration ( * ( in_addr * ) & entry . first ) ) ;
2018-03-29 17:01:57 -04:00
}
return banList ;
}
2019-07-07 20:56:15 +00:00
uint32_t CNetwork : : GetUniques ( )
2019-01-19 18:57:19 -06:00
{
2020-06-06 23:22:18 +00:00
if ( m_clients . size ( ) = = 0 )
2019-01-19 18:57:19 -06:00
return 0 ;
2020-06-06 23:22:18 +00:00
std : : list < std : : string > addresses ;
2019-01-19 18:57:19 -06:00
std : : string addr = " " ;
2020-06-06 23:22:18 +00:00
for ( auto entry : m_clients )
2019-01-19 18:57:19 -06:00
{
2020-06-06 23:22:18 +00:00
if ( entry . second )
2019-01-19 18:57:19 -06:00
{
2020-06-06 23:22:18 +00:00
addr = inet_ntoa ( entry . second - > GetHostAddress ( ) - > sin_addr ) ;
2019-01-19 18:57:19 -06:00
if ( addr ! = " " )
2020-06-06 23:22:18 +00:00
addresses . push_back ( addr ) ;
2019-01-19 18:57:19 -06:00
}
}
2020-06-06 23:22:18 +00:00
addresses . unique ( ) ;
2019-01-19 18:57:19 -06:00
2020-06-06 23:22:18 +00:00
uint32_t count = addresses . size ( ) ;
2019-01-19 18:57:19 -06:00
return count ;
}
2020-06-06 23:22:18 +00:00
AuthenticateUserQuery : : AuthenticateUserQuery ( sockaddr_in connection , BlobPacket_s * blob )
: m_connection ( connection )
{
BinaryReader loginRequest ( blob - > data , blob - > header . wSize ) ;
m_version = loginRequest . ReadString ( ) ;
loginRequest . ReadUInt32 ( ) ; // 0x20 ?
m_auth_type = loginRequest . ReadUInt32 ( ) ;
loginRequest . ReadUInt32 ( ) ; // 0x0 ?
m_timestamp = loginRequest . ReadUInt32 ( ) ; // client unix timestamp
switch ( m_auth_type )
{
case 1 :
{
// -a username:password
char * login_credentials ;
login_credentials = loginRequest . ReadString ( ) ;
char * szPassword = strstr ( login_credentials , " : " ) ;
if ( ! szPassword ) return ;
* ( szPassword ) = ' \0 ' ;
szPassword + + ;
m_username = login_credentials ;
m_password = szPassword ;
// there are two empty ints
loginRequest . ReadUInt32 ( ) ;
loginRequest . ReadUInt32 ( ) ;
break ;
}
case 2 :
{
// -a username -v password
char * login_credentials ;
login_credentials = loginRequest . ReadString ( ) ;
m_username = login_credentials ;
// nothing
loginRequest . ReadUInt32 ( ) ;
// length of encoded data following
uint32_t dataLen = loginRequest . ReadUInt32 ( ) ;
// data is here packed_short,char[packed_short]
uint16_t len = loginRequest . ReadCompressedUInt16 ( ) ;
login_credentials = ( char * ) loginRequest . ReadArray ( len ) ;
m_password = login_credentials ;
break ;
}
default :
m_auth_type = 0 ;
break ;
}
}
bool AuthenticateUserQuery : : PerformQuery ( MYSQL * c )
{
if ( ! c )
return false ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( m_username . compare ( " acservertracker " ) = = 0 )
{
g_pNetwork - > SendConnectLoginFailure ( & m_connection , STR_LOGIN_FAILED , nullptr , nullptr ) ;
return true ;
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( m_version . compare ( " 1802 " ) ! = 0 )
{
g_pNetwork - > SendConnectLoginFailure ( & m_connection , STR_LOGIN_CLIENT_VERSION , nullptr , nullptr ) ;
return true ;
}
if ( m_auth_type = = 0 ) // case 3 was turbine ticket method, took that out
{
g_pNetwork - > SendConnectLoginFailure ( & m_connection , STR_LOGIN_INVALID_AUTH , nullptr , nullptr ) ;
return true ;
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
AccountInformation_t account = { 0 } ;
int err = 0 ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( ! g_pDBIO - > VerifyAccount ( c , m_username . c_str ( ) , m_password . c_str ( ) , & account , & err ) )
{
if ( err = = VERIFYACCOUNT_ERROR_DOESNT_EXIST & & g_pConfig - > AutoCreateAccounts ( ) )
{
char * ipaddr = inet_ntoa ( m_connection . sin_addr ) ;
if ( g_pDBIO - > CreateAccount ( c , m_username . c_str ( ) , m_password . c_str ( ) , & err , ipaddr ) )
{
g_pDBIO - > VerifyAccount ( c , m_username . c_str ( ) , m_password . c_str ( ) , & account , & err ) ;
}
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
if ( err ! = DBIO_ERROR_NONE )
{
g_pNetwork - > SendConnectLoginFailure ( & m_connection , STR_LOGIN_FAILED , m_username . c_str ( ) , nullptr ) ;
return true ;
}
}
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
g_pNetwork - > AcceptClientLogin ( & m_connection , account , m_timestamp , 0 , 0 ) ;
2018-03-29 17:01:57 -04:00
2020-06-06 23:22:18 +00:00
// if we get this far, go ahead and bail the attempt
return true ;
}