polserver/pol-core/pol/network/clientio.cpp

280 lines
6.9 KiB
C++

/** @file
*
* @par History
* - 2009/12/04 Turley: Crypto cleanup - Tomi
*/
#include <errno.h>
#include <mutex>
#include <stddef.h>
#include <string>
#include "../../clib/fdump.h"
#include "../../clib/logfacility.h"
#include "../../clib/network/sockets.h"
#include "../../clib/passert.h"
#include "../../clib/refptr.h"
#include "../../clib/spinlock.h"
#include "../crypt/cryptbase.h"
#include "../ctable.h"
#include "../globals/network.h"
#include "../globals/state.h"
#include "../packetscrobj.h"
#include "../polsem.h"
#include "../polsig.h"
#include "client.h"
#include "clienttransmit.h"
#include "packethelper.h"
#include "packethooks.h"
#include "packets.h"
#include <format/format.h>
namespace Pol
{
namespace Network
{
std::string Client::ipaddrAsString() const
{
return AddressToString( &this->ipaddr );
}
void Client::recv_remaining( int total_expected )
{
int count;
int max_expected = total_expected - bytes_received;
{
std::lock_guard<std::mutex> lock( _SocketMutex );
count = cryptengine->Receive( &buffer[bytes_received], max_expected, csocket );
}
if ( count > 0 )
{
passert( count <= max_expected );
bytes_received += count;
counters.bytes_received += count;
Core::networkManager.polstats.bytes_received += count;
}
else if ( count == 0 ) // graceful close
{
disconnect = true;
}
else
{
int errn = socket_errno;
if ( errn != SOCKET_ERRNO( EWOULDBLOCK ) )
disconnect = true;
}
}
void Client::recv_remaining_nocrypt( int total_expected )
{
int count;
{
std::lock_guard<std::mutex> lock( _SocketMutex );
count = recv( csocket, (char*)&buffer[bytes_received], total_expected - bytes_received, 0 );
}
if ( count > 0 )
{
bytes_received += count;
counters.bytes_received += count;
Core::networkManager.polstats.bytes_received += count;
}
else if ( count == 0 ) // graceful close
{
disconnect = true;
}
else
{
int errn = socket_errno;
if ( errn != SOCKET_ERRNO( EWOULDBLOCK ) )
disconnect = true;
}
}
/* NOTE: If this changes, code in client.cpp must change - pause() and restart() use
pre-encrypted values of 33 00 and 33 01.
*/
void Client::transmit_encrypted( const void* data, int len )
{
THREAD_CHECKPOINT( active_client, 100 );
const unsigned char* cdata = (const unsigned char*)data;
unsigned char* pch;
int i;
int bidx; // Offset in output byte
EncryptedPktBuffer* outbuffer =
PktHelper::RequestPacket<EncryptedPktBuffer>( ENCRYPTEDPKTBUFFER );
pch = reinterpret_cast<unsigned char*>( outbuffer->getBuffer() );
bidx = 0;
THREAD_CHECKPOINT( active_client, 101 );
for ( i = 0; i < len; i++ )
{
THREAD_CHECKPOINT( active_client, 102 );
unsigned char ch = cdata[i];
int nbits = Core::keydesc[ch].nbits;
unsigned short inval = Core::keydesc[ch].bits_reversed;
THREAD_CHECKPOINT( active_client, 103 );
while ( nbits-- )
{
THREAD_CHECKPOINT( active_client, 104 );
*pch <<= 1;
if ( inval & 1 )
*pch |= 1;
bidx++;
if ( bidx == 8 )
{
THREAD_CHECKPOINT( active_client, 105 );
pch++;
bidx = 0;
}
THREAD_CHECKPOINT( active_client, 106 );
inval >>= 1;
}
THREAD_CHECKPOINT( active_client, 107 );
}
THREAD_CHECKPOINT( active_client, 108 );
{
int nbits = Core::keydesc[0x100].nbits;
unsigned short inval = Core::keydesc[0x100].bits_reversed;
THREAD_CHECKPOINT( active_client, 109 );
while ( nbits-- )
{
THREAD_CHECKPOINT( active_client, 110 );
*pch <<= 1;
if ( inval & 1 )
*pch |= 1;
bidx++;
THREAD_CHECKPOINT( active_client, 111 );
if ( bidx == 8 )
{
pch++;
bidx = 0;
}
THREAD_CHECKPOINT( active_client, 112 );
inval >>= 1;
}
}
THREAD_CHECKPOINT( active_client, 113 );
if ( bidx == 0 )
{
pch--;
}
else
{
*pch <<= ( 8 - bidx );
}
THREAD_CHECKPOINT( active_client, 114 );
passert_always( pch - reinterpret_cast<unsigned char*>( outbuffer->buffer ) + 1 <=
int( sizeof outbuffer->buffer ) );
THREAD_CHECKPOINT( active_client, 115 );
xmit( &outbuffer->buffer, static_cast<unsigned short>(
pch - reinterpret_cast<unsigned char*>( outbuffer->buffer ) + 1 ) );
PktHelper::ReAddPacket( outbuffer );
THREAD_CHECKPOINT( active_client, 116 );
}
void Client::transmit( const void* data, int len, bool needslock )
{
ref_ptr<Core::BPacket> p;
bool handled = false;
// see if the outgoing packet has a SendFunction installed. If so call it. It may or may not
// want us to continue sending the packet. If it does, handled will be false, and data, len, and p
// will be altered. data has the new packet data to send, len the new length, and p, a ref counted
// pointer to the packet object.
//
// If there is no outgoing packet script, handled will be false, and the passed params will be
// unchanged.
{
PacketHookData* phd = nullptr;
handled = GetAndCheckPacketHooked( this, data, phd );
if ( handled )
{
if ( needslock )
{
Core::PolLock lock;
std::lock_guard<std::mutex> guard( _SocketMutex );
CallOutgoingPacketExportedFunction( this, data, len, p, phd, handled );
}
else
{
std::lock_guard<std::mutex> guard( _SocketMutex );
CallOutgoingPacketExportedFunction( this, data, len, p, phd, handled );
}
}
}
if ( handled )
return;
unsigned char msgtype = *(const char*)data;
{
Clib::SpinLockGuard guard( _fpLog_lock );
if ( !fpLog.empty() )
{
fmt::Writer tmp;
tmp << "Server -> Client: 0x" << fmt::hexu( msgtype ) << ", " << len << " bytes\n";
Clib::fdump( tmp, data, len );
FLEXLOG( fpLog ) << tmp.str() << "\n";
}
}
std::lock_guard<std::mutex> guard( _SocketMutex );
if ( disconnect )
{
POLLOG_INFO << "Warning: Trying to send to a disconnected client! \n";
fmt::Writer tmp;
tmp << "Server -> Client: 0x" << fmt::hexu( msgtype ) << ", " << len << " bytes\n";
Clib::fdump( tmp, data, len );
POLLOG_INFO << tmp.str() << "\n";
return;
}
if ( last_xmit_buffer )
{
Core::networkManager.queuedmode_iostats.sent[msgtype].count++;
Core::networkManager.queuedmode_iostats.sent[msgtype].bytes += len;
}
Core::networkManager.iostats.sent[msgtype].count++;
Core::networkManager.iostats.sent[msgtype].bytes += len;
if ( encrypt_server_stream )
{
pause();
transmit_encrypted( data, len );
}
else
{
xmit( data, static_cast<unsigned short>( len ) );
// _xmit( client->csocket, data, len );
}
}
void transmit( Client* client, const void* data, int len )
{
Core::networkManager.clientTransmit->AddToQueue( client, data, len );
}
void Client::Disconnect()
{
if ( this->isConnected() )
{
this->preDisconnect = true;
Core::networkManager.clientTransmit->QueueDisconnection( this );
}
}
} // namespace Network
} // namespace Pol