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"
# include "Database.h"
# include "Database2.h"
# include "DatabaseIO.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"
// 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
m_ClientArray = new CClient * [ m_MaxClients ] ;
memset ( m_ClientArray , 0 , sizeof ( CClient * ) * m_MaxClients ) ;
m_ClientSlots = new CClient * [ m_MaxClients + 1 ] ;
memset ( m_ClientSlots , 0 , sizeof ( CClient * ) * ( m_MaxClients + 1 ) ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 1 ; i < = m_MaxClients ; i + + )
2018-03-29 17:01:57 -04:00
{
m_OpenSlots . push_back ( i ) ;
}
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
2018-08-15 21:29:07 -05:00
for ( int i = 0 ; i < m_NumClients ; i + + )
2018-03-29 17:01:57 -04:00
{
2018-08-15 21:29:07 -05:00
SafeDelete ( m_ClientArray [ i ] ) ;
2018-03-29 17:01:57 -04:00
}
_queuedIncoming . clear ( ) ;
_queuedOutgoing . clear ( ) ;
SafeDeleteArray ( m_ClientSlots ) ;
SafeDeleteArray ( m_ClientArray ) ;
}
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
// #if defined(_WINDOWS)
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
// WSADATA wsaData;
// USHORT wVersionRequested = 0x0202;
// WSAStartup(wVersionRequested, &wsaData);
// #endif
xsocket : : socket_init ( ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
// SOCKADDR_IN local_read;
// local_read.sin_family = AF_INET;
// local_read.sin_addr = m_addr;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
// m_read_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// m_write_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2018-08-19 09:37:41 -05: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
2019-07-07 20:56:15 +00:00
// local_read.sin_port = htons(m_port);
// if (bind(m_read_sock, reinterpret_cast<const sockaddr*>(&local_read), sizeof(SOCKADDR_IN)))
// {
// WINLOG(Temp, Normal, "Failed bind on recv port %u!\n", m_port);
// SERVER_ERROR << "Failed bind on recv port:" << m_port;
// }
// SOCKADDR_IN local_write;
// local_write.sin_family = AF_INET;
// local_write.sin_addr = m_addr;
// WORD sport = m_port + 1;
// local_write.sin_port = htons(sport);
// if (bind(m_write_sock, reinterpret_cast<const sockaddr*>(&local_write), sizeof(SOCKADDR_IN)))
// {
// WINLOG(Temp, Normal, "Failed bind on send port %u!\n", sport);
// SERVER_ERROR << "Failed bind on send port:" << sport;
// }
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 ) ;
// unsigned long arg = 1;
// ioctlsocket(m_read_sock, FIONBIO, &arg);
// setsockopt(m_read_sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffsize, sizeof(buffsize));
// setsockopt(m_read_sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffsize, sizeof(buffsize));
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
// ioctlsocket(m_write_sock, FIONBIO, &arg);
// setsockopt(m_write_sock, SOL_SOCKET, SO_SNDBUF, (char *)&buffsize, sizeof(buffsize));
// setsockopt(m_write_sock, SOL_SOCKET, SO_RCVBUF, (char *)&buffsize, sizeof(buffsize));
2018-08-15 21:29:07 -05:00
}
void CNetwork : : Shutdown ( )
{
2019-07-07 20:56:15 +00:00
//closesocket(m_read_sock);
//closesocket(m_write_sock);
m_read_sock . close ( ) ;
m_write_sock . close ( ) ;
xsocket : : socket_shutdown ( ) ;
// #if defined(_WINDOWS)
// WSACleanup();
// #endif
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 ( )
{
2018-08-19 09:37:41 -05:00
// one second delay
//timeval waittime = { 1, 0 };
//fd_set fd = { 0 };
2018-08-15 21:29:07 -05:00
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
{
2018-08-19 09:37:41 -05:00
//FD_ZERO(&fd);
//FD_SET(m_read_sock, &fd);
//FD_SET(m_write_sock, &fd);
//select(0, nullptr, &fd, nullptr, &waittime);
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))
if ( SendPacket ( queued . useReadStream ? m_read_sock : m_read_sock , & queued . addr , queued . data . get ( ) , queued . len ) )
2018-08-16 12:48:45 -05:00
{
2018-08-15 21:29:07 -05:00
_queuedOutgoing . erase ( entry ) ;
2018-08-16 12:48:45 -05:00
}
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
{
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 = sendto(socket, (char *)data, len, 0, (sockaddr *)peer, sizeof(SOCKADDR_IN));
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 ) ;
*/
}
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 = recvfrom(socket, (char *)buffer, 0x1E4, NULL, (sockaddr *)&clientaddr, &clientaddrlen);
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 ;
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 ;
qp . recvTime = g_pGlobals - > UpdateTime ( ) ;
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
2019-07-07 20:56:15 +00:00
// blob->header.dwCRC -= CalcTransportCRC((uint32_t *)blob);
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
*/
/*
if ( ! wRecID )
{
ProcessConnectionless ( & clientaddr , blob ) ;
}
else
{
CClient * client = ValidateClient ( wRecID , & clientaddr ) ;
if ( client )
client - > IncomingBlob ( blob ) ;
}
*/
}
}
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 ( )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < m_NumClients ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( CClient * client = m_ClientArray [ i ] )
{
if ( client - > IsAlive ( ) & & client - > GetEvents ( ) )
{
2018-04-29 18:07:18 -07:00
client - > GetEvents ( ) - > ForceLogout ( ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
void CNetwork : : CompleteLogoutAll ( )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < m_NumClients ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( CClient * client = m_ClientArray [ i ] )
{
if ( client - > IsAlive ( ) & & client - > GetEvents ( ) )
{
//todo: send the user to the appropriate server connection lost screen.
BinaryWriter EnterPortal ;
2019-07-07 20:56:15 +00:00
EnterPortal . Write < uint32_t > ( 0xF751 ) ;
EnterPortal . Write < uint32_t > ( 0 ) ;
2018-03-29 17:01:57 -04:00
client - > SendNetMessage ( EnterPortal . GetData ( ) , EnterPortal . GetSize ( ) , OBJECT_MSG ) ;
BinaryWriter popupString ;
2019-07-07 20:56:15 +00:00
popupString . Write < uint32_t > ( 4 ) ;
2018-03-29 17:01:57 -04:00
popupString . WriteString ( " The server has shutdown. " ) ;
client - > SendNetMessage ( & popupString , PRIVATE_MSG , FALSE , FALSE ) ;
}
}
}
}
void CNetwork : : Think ( )
{
ProcessQueuedIncoming ( ) ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < m_NumClients ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( CClient * client = m_ClientArray [ i ] )
{
client - > Think ( ) ;
if ( ! client - > IsAlive ( ) )
{
KillClient ( client - > GetSlot ( ) ) ;
}
}
}
2019-02-07 00:17:17 -06:00
CClient * * end = m_ClientArray + m_NumClients ;
2019-07-07 20:56:15 +00:00
# if defined(__cpp_lib_parallel_algorithm)
2019-02-07 00:17:17 -06:00
std : : for_each ( std : : execution : : par , m_ClientArray , end , [ ] ( CClient * & client )
2019-07-07 20:56:15 +00:00
# else
std : : for_each ( m_ClientArray , end , [ ] ( CClient * & client )
# endif
2019-02-07 00:17:17 -06:00
{
client - > ThinkOutbound ( ) ;
} ) ;
2018-03-29 17:01:57 -04:00
}
CClient * CNetwork : : GetClient ( WORD slot )
{
if ( ! slot | | slot > m_MaxClients )
return NULL ;
return m_ClientSlots [ slot ] ;
}
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 )
{
if ( CClient * pClient = GetClient ( slot ) )
{
2018-04-27 23:00:19 -07:00
SERVER_INFO < < " Client " < < pClient - > GetAccount ( ) < < " ( " < < inet_ntoa ( pClient - > GetHostAddress ( ) - > sin_addr ) < < " ) disconnected " ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t arrayPos = pClient - > GetArrayPos ( ) ;
2018-03-29 17:01:57 -04:00
delete pClient ;
m_NumClients - - ;
m_ClientArray [ arrayPos ] = m_ClientArray [ m_NumClients ] ;
m_ClientArray [ m_NumClients ] = NULL ;
m_ClientSlots [ slot ] = NULL ;
m_OpenSlots . push_front ( slot ) ;
if ( m_ClientArray [ arrayPos ] )
{
m_ClientArray [ arrayPos ] - > SetArrayPos ( arrayPos ) ;
}
// m_server->Stats().UpdateClientList(NULL, 0);
}
}
CClient * CNetwork : : FindClientByAccount ( const char * account )
{
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < m_NumClients ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( CClient * client = m_ClientArray [ i ] )
{
if ( client - > CheckAccount ( account ) )
return client ;
}
}
return NULL ;
}
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 )
{
BinaryReader loginRequest ( p - > data , p - > header . wSize ) ;
char * version_string = loginRequest . ReadString ( ) ;
2019-04-13 18:18:28 +00:00
if ( strncmp ( version_string , " 1802 " , 4 ) )
{
SendConnectLoginFailure ( addr , STR_LOGIN_CLIENT_VERSION , nullptr , nullptr ) ;
return ;
}
2019-07-07 20:56:15 +00:00
loginRequest . ReadUInt32 ( ) ; // 0x20 ?
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t auth_method = loginRequest . ReadUInt32 ( ) ;
loginRequest . ReadUInt32 ( ) ; // 0x0 ?
uint32_t client_unix_timestamp = loginRequest . ReadUInt32 ( ) ; // client unix timestamp
2018-03-29 17:01:57 -04:00
char * login_credentials ;
if ( auth_method ! = 1 ) // case 3 was turbine ticket method, took that out
return ;
login_credentials = loginRequest . ReadString ( ) ;
2019-07-07 20:56:15 +00:00
uint32_t portal_stamp = loginRequest . ReadUInt32 ( ) ;
uint32_t cell_stamp = loginRequest . ReadUInt32 ( ) ;
2018-03-29 17:01:57 -04:00
if ( loginRequest . GetLastError ( ) )
return ;
char * szPassword = strstr ( login_credentials , " : " ) ;
if ( ! szPassword ) return ;
* ( szPassword ) = ' \0 ' ;
szPassword + + ;
if ( ! strcmp ( login_credentials , " acservertracker " ) )
{
2019-04-13 18:18:28 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_FAILED , nullptr , nullptr ) ;
2018-03-29 17:01:57 -04:00
return ;
}
// Try to login to the login_credentials
AccountInformation_t accountInfo ;
int error = 0 ;
if ( ! g_pDBIO - > VerifyAccount ( login_credentials , szPassword , & accountInfo , & error ) )
{
if ( error = = VERIFYACCOUNT_ERROR_DOESNT_EXIST & & g_pConfig - > AutoCreateAccounts ( ) )
{
std : : string ipaddress = inet_ntoa ( addr - > sin_addr ) ;
// try to create the login_credentials
if ( g_pDBIO - > CreateAccount ( login_credentials , szPassword , & error , ipaddress . c_str ( ) ) )
{
// now try to verify the newly created login_credentials
if ( ! g_pDBIO - > VerifyAccount ( login_credentials , szPassword , & accountInfo , & error ) )
{
// fail
2019-04-13 18:18:28 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_FAILED , login_credentials , szPassword ) ;
2018-03-29 17:01:57 -04:00
return ;
}
}
else
{
// fail
2019-04-13 18:18:28 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_FAILED , login_credentials , szPassword ) ;
2018-03-29 17:01:57 -04:00
return ;
}
}
else
{
// fail
2019-04-13 18:18:28 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_FAILED , login_credentials , szPassword ) ;
2018-03-29 17:01:57 -04:00
return ;
}
}
CClient * client = FindClientByAccount ( accountInfo . username . c_str ( ) ) ;
if ( client )
{
2020-02-23 12:01:33 -08:00
// Check existing client m_vars.ClientLoginUnixTime vs new connection request and ignore if 5 secs have not elapsed.
if ( stricmp ( client - > GetAccount ( ) , " admin " ) & & ( client - > GetLoginTime ( ) + 5 < = client_unix_timestamp ) )
2018-03-29 17:01:57 -04:00
{
KickClient ( client ) ;
2020-02-23 12:01:33 -08:00
2018-03-29 17:01:57 -04:00
}
else
{
2020-02-23 12:01:33 -08:00
SERVER_INFO < < " Client " < < client - > GetSlot ( ) < < " ( " < < client - > GetAccount ( ) < < " ) is being ignored due to frequency of login requests. " ;
2018-03-29 17:01:57 -04:00
return ;
}
}
WORD slot = AllocOpenClientSlot ( ) ;
if ( ! slot )
{
// Server unavailable.
2019-04-13 18:18:28 +00:00
SendConnectLoginFailure ( addr , STR_LOGIN_SERVER_FULL , nullptr , nullptr ) ;
2019-07-07 20:56:15 +00:00
//CREATEBLOB(ServerFull, sizeof(uint32_t));
//*((uint32_t *)ServerFull->data) = 0x00000005;
2018-03-29 17:01:57 -04:00
2019-04-13 18:18:28 +00:00
//SendConnectlessBlob(addr, ServerFull, BT_ERROR, 0, 0, true);
2018-03-29 17:01:57 -04:00
2019-04-13 18:18:28 +00:00
//DELETEBLOB(ServerFull);
2018-03-29 17:01:57 -04:00
return ;
}
2018-08-19 09:37:41 -05:00
SERVER_INFO < < " Client " < < login_credentials < < " ( " < < inet_ntoa ( addr - > sin_addr ) < < " : " < < ntohs ( addr - > sin_port ) < < " ) connected on slot " < < slot ;
2018-03-29 17:01:57 -04:00
client = m_ClientSlots [ slot ] = new CClient ( addr , slot , accountInfo ) ;
client - > SetLoginData ( client_unix_timestamp , portal_stamp , cell_stamp ) ;
m_ClientArray [ m_NumClients ] = client ;
client - > SetArrayPos ( m_NumClients ) ;
m_NumClients + + ;
// 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
if ( IsBannedIP ( addr - > sin_addr ) | | accountInfo . banned = = true )
{
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 ) ;
g_pDBIO - > UpdateBan ( accountInfo . id , 0 ) ;
}
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
}
}
WORD CNetwork : : AllocOpenClientSlot ( )
{
// Allocate an available slot for a connecting client
if ( m_OpenSlots . empty ( ) )
return 0 ;
2019-07-07 20:56:15 +00:00
uint32_t slot = * m_OpenSlots . begin ( ) ;
2018-03-29 17:01:57 -04:00
m_OpenSlots . pop_front ( ) ;
return slot ;
}
void CNetwork : : ProcessConnectionless ( sockaddr_in * peer , BlobPacket_s * blob )
{
2019-07-07 20:56:15 +00:00
uint32_t dwFlags = blob - > header . dwFlags ;
2018-03-29 17:01:57 -04:00
if ( dwFlags = = BT_LOGIN )
{
2019-01-25 02:26:45 -06:00
ConnectionRequest ( peer , blob ) ;
2018-03-29 17:01:57 -04:00
return ;
}
// LOG(Network, Verbose, "Unhandled connectionless packet received: 0x%08X Look into this\n", dwFlags);
}
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 ;
SaveBans ( ) ;
}
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
SaveBans ( ) ;
}
bool CNetwork : : RemoveBan ( in_addr ipaddr )
{
if ( m_Bans . m_BanTable . lookup ( ipaddr . s_addr ) )
{
m_Bans . m_BanTable . erase ( ipaddr . s_addr ) ;
SaveBans ( ) ;
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
{
if ( ! m_NumClients )
return 0 ;
std : : list < std : : string > _addresses ;
std : : string addr = " " ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < m_NumClients ; i + + )
2019-01-19 18:57:19 -06:00
{
if ( CClient * client = m_ClientArray [ i ] )
{
addr = inet_ntoa ( client - > GetHostAddress ( ) - > sin_addr ) ;
if ( addr ! = " " )
_addresses . push_back ( addr ) ;
}
}
_addresses . unique ( ) ;
2019-07-07 20:56:15 +00:00
uint32_t count = _addresses . size ( ) ;
2019-01-19 18:57:19 -06:00
return count ;
}
2018-03-29 17:01:57 -04:00