mirror of
https://github.com/therealKyp/Earth-and-Beyond-server
synced 2026-08-13 22:23:03 -04:00
630 lines
16 KiB
C++
630 lines
16 KiB
C++
|
|
// Connection.cpp
|
||
|
|
//
|
||
|
|
|
||
|
|
#include "Net7.h"
|
||
|
|
#include "Connection.h"
|
||
|
|
#include "ServerManager.h"
|
||
|
|
#include "PacketStructures.h"
|
||
|
|
#include "PlayerClass.h"
|
||
|
|
|
||
|
|
Connection::Connection()
|
||
|
|
{
|
||
|
|
m_ConnectionActive = true; // Mark this as an active connection
|
||
|
|
m_TcpThreadRunning = false; // Start thread in non-running mode
|
||
|
|
m_TcpThreadTerminated = false;
|
||
|
|
m_KeysExchanged = false;
|
||
|
|
|
||
|
|
// Initialize settings
|
||
|
|
m_Socket = INVALID_SOCKET;
|
||
|
|
m_TcpPort = 0;
|
||
|
|
m_ServerType = 0;
|
||
|
|
m_IPaddr = 0;
|
||
|
|
m_AvatarID = 0;
|
||
|
|
m_LastOwner = (0);
|
||
|
|
|
||
|
|
m_InactivityTimer = 0;
|
||
|
|
m_MaxInactivityTime = 0; // Infinite
|
||
|
|
|
||
|
|
m_PacketLoggingEnabled = false; // Disable packet logging
|
||
|
|
|
||
|
|
m_SendQueue = new MessageQueue(g_ServerMgr->GetTCPCBuffer());
|
||
|
|
|
||
|
|
#ifdef WIN32
|
||
|
|
UINT uiThreadId = 0;
|
||
|
|
m_RecvThreadHandle = (HANDLE)_beginthreadex(NULL, 1024, SocketRecvThread, this, 0, &uiThreadId);
|
||
|
|
#else
|
||
|
|
pthread_mutex_init(&m_RecvThreadMtx, NULL);
|
||
|
|
pthread_cond_init(&m_RecvThreadCond, NULL);
|
||
|
|
pthread_create(&m_RecvThreadHandle, NULL, SocketRecvThread, this);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (!m_RecvThreadHandle) LogMessage("Unable to create another thread for TCP Connection\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
Connection * Connection::ReSetConnection(SOCKET s, ServerManager &server_mgr, short port, int server_type, unsigned long* ip_addr)
|
||
|
|
{
|
||
|
|
if (!m_RecvThreadHandle) // This should never be needed, but it's in here just in case.
|
||
|
|
{
|
||
|
|
LogMessage("!Restarting TCP Connection receive thread\n");
|
||
|
|
#ifdef WIN32
|
||
|
|
UINT uiThreadId = 0;
|
||
|
|
m_RecvThreadHandle = (HANDLE)_beginthreadex(NULL, 1024, SocketRecvThread, this, 0, &uiThreadId);
|
||
|
|
#else
|
||
|
|
pthread_mutex_init(&m_RecvThreadMtx, NULL);
|
||
|
|
pthread_cond_init(&m_RecvThreadCond, NULL);
|
||
|
|
pthread_create(&m_RecvThreadHandle, NULL, SocketRecvThread, this);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
m_Mutex.Lock();
|
||
|
|
|
||
|
|
m_ConnectionActive = true; // Mark this as an active connection
|
||
|
|
m_PacketLoggingEnabled = false; // Disable packet logging
|
||
|
|
m_KeysExchanged = false;
|
||
|
|
m_LoginHandoff = false;
|
||
|
|
m_InactivityTimer = 0;
|
||
|
|
|
||
|
|
// Temporarily set the AvatarID to 1, otherwise it might get killed off
|
||
|
|
// too soon with a heavy load (lots of connections)
|
||
|
|
m_AvatarID = 1;
|
||
|
|
|
||
|
|
m_Socket = s;
|
||
|
|
m_TcpPort = port;
|
||
|
|
m_ServerType = server_type;
|
||
|
|
|
||
|
|
if (ip_addr) m_IPaddr = *ip_addr;
|
||
|
|
|
||
|
|
m_Mutex.Unlock();
|
||
|
|
|
||
|
|
m_SendQueue->ResetQueue();
|
||
|
|
|
||
|
|
LogMessage("[%d] Reanimating TCP Connection receive thread\n", m_RecvThreadHandle);
|
||
|
|
|
||
|
|
WakeupThread();
|
||
|
|
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
Connection::~Connection()
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Connection Destroyed\n", m_RecvThreadHandle);
|
||
|
|
|
||
|
|
KillConnection();
|
||
|
|
|
||
|
|
// Let thread know it is terminated.
|
||
|
|
if (!m_TcpThreadTerminated)
|
||
|
|
{
|
||
|
|
m_TcpThreadTerminated = true;
|
||
|
|
WakeupThread();
|
||
|
|
|
||
|
|
m_Mutex.Lock();
|
||
|
|
Sleep(1);
|
||
|
|
m_Mutex.Unlock();
|
||
|
|
}
|
||
|
|
|
||
|
|
delete m_SendQueue;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Connection::IsActive()
|
||
|
|
{
|
||
|
|
// Good opportunity to check g_ServerShutdown
|
||
|
|
if (g_ServerShutdown) WakeupThread();
|
||
|
|
|
||
|
|
return m_ConnectionActive;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Will return false if timeout expired or error occured.
|
||
|
|
bool Connection::SocketReady(int ttimeout)
|
||
|
|
{
|
||
|
|
fd_set fds;
|
||
|
|
struct timeval timeout;
|
||
|
|
long ret;
|
||
|
|
|
||
|
|
FD_ZERO(&fds);
|
||
|
|
FD_SET(m_Socket, &fds);
|
||
|
|
|
||
|
|
if (ttimeout >= 0)
|
||
|
|
{
|
||
|
|
timeout.tv_sec = ttimeout;
|
||
|
|
timeout.tv_usec = 0;
|
||
|
|
|
||
|
|
ret = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ret = select(sizeof(fds)*8, &fds, NULL, NULL, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
return bool(ret > 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::WakeupThread()
|
||
|
|
{
|
||
|
|
m_TcpThreadRunning = true;
|
||
|
|
|
||
|
|
#ifndef WIN32
|
||
|
|
pthread_cond_signal(&m_RecvThreadCond);
|
||
|
|
#else
|
||
|
|
ResumeThread(m_RecvThreadHandle);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::Send(unsigned char *Buffer, int length)
|
||
|
|
{
|
||
|
|
if (m_PacketLoggingEnabled)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Adding packet to Send Queue, length=%d\n", m_RecvThreadHandle, length);
|
||
|
|
DumpBuffer(Buffer, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Mutexed, so thread safe. Not sure about DumpBuffer... (didn't look)
|
||
|
|
m_SendQueue->Add(Buffer, length, m_AvatarID);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::SetRC4Key(unsigned char *rc4_key)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
LogMessage("SetRC4Key: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||
|
|
rc4_key[0],
|
||
|
|
rc4_key[1],
|
||
|
|
rc4_key[2],
|
||
|
|
rc4_key[3],
|
||
|
|
rc4_key[4],
|
||
|
|
rc4_key[5],
|
||
|
|
rc4_key[6],
|
||
|
|
rc4_key[7] );
|
||
|
|
*/
|
||
|
|
|
||
|
|
m_CryptOut.PrepareKey(rc4_key, RC4_KEY_SIZE);
|
||
|
|
m_CryptIn.PrepareKey(rc4_key, RC4_KEY_SIZE);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Connection::DoKeyExchange()
|
||
|
|
{
|
||
|
|
unsigned char buffer[128];
|
||
|
|
unsigned char *p = buffer;
|
||
|
|
int length;
|
||
|
|
|
||
|
|
// Send the RSA Public Key to the client
|
||
|
|
length = m_WestwoodRSA.GetModulus(&p);
|
||
|
|
length += m_WestwoodRSA.GetPublicExponent(&p);
|
||
|
|
|
||
|
|
if ( (send(m_Socket, (char *) buffer, length, 0) != length) || // Did send fail?
|
||
|
|
!SocketReady() || // Did the socket timeout?
|
||
|
|
(recv(m_Socket, (char *) buffer, 4, 0) != 4) ) // Never got a 4-byte header?
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
long key_length = (long) ntohl((*((unsigned long *) buffer)));
|
||
|
|
if ( (key_length < WWRSA_BLOCK_SIZE) || (key_length > (WWRSA_BLOCK_SIZE + 1)) )
|
||
|
|
{
|
||
|
|
LogMessage("[%d] ERROR: DoKeyExchange key_length = %d\n", m_RecvThreadHandle, key_length);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the encrypted RC4 Session Key response from the client
|
||
|
|
length = recv(m_Socket, (char *) buffer, key_length, 0);
|
||
|
|
if (length != key_length)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] ERROR: DoKeyExchange key_length = %d, recv_length = %d\n", m_RecvThreadHandle, key_length, length);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ignore leading 0 if present
|
||
|
|
p = buffer;
|
||
|
|
if ( (key_length == WWRSA_BLOCK_SIZE + 1) && (*p == 0) )
|
||
|
|
{
|
||
|
|
key_length--;
|
||
|
|
p++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Decrypt the RC4 Session Key
|
||
|
|
unsigned char rc4key[WWRSA_BLOCK_SIZE];
|
||
|
|
if (!m_WestwoodRSA.Decrypt(p, WWRSA_BLOCK_SIZE, rc4key))
|
||
|
|
{
|
||
|
|
LogMessage("[%d] ERROR: DoKeyExchange m_WestwoodRSA.Decrypt failed\n", m_RecvThreadHandle);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned char rc4_key_buffer[RC4_KEY_SIZE];
|
||
|
|
// Reverse the order of the decrypted RC4 Session Key
|
||
|
|
rc4_key_buffer[0] = rc4key[0x3f];
|
||
|
|
rc4_key_buffer[1] = rc4key[0x3e];
|
||
|
|
rc4_key_buffer[2] = rc4key[0x3d];
|
||
|
|
rc4_key_buffer[3] = rc4key[0x3c];
|
||
|
|
rc4_key_buffer[4] = rc4key[0x3b];
|
||
|
|
rc4_key_buffer[5] = rc4key[0x3a];
|
||
|
|
rc4_key_buffer[6] = rc4key[0x39];
|
||
|
|
rc4_key_buffer[7] = rc4key[0x38];
|
||
|
|
|
||
|
|
SetRC4Key(rc4_key_buffer);
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Connection::DoClientKeyExchange()
|
||
|
|
{
|
||
|
|
// Generate RC4 key
|
||
|
|
unsigned int i = 0;
|
||
|
|
unsigned char rc4key[RC4_KEY_SIZE];
|
||
|
|
unsigned char buffer[128];
|
||
|
|
|
||
|
|
memset(rc4key, 0, sizeof(rc4key));
|
||
|
|
SetRC4Key(rc4key);
|
||
|
|
|
||
|
|
// Receive the pubic key packet
|
||
|
|
Sleep(20);
|
||
|
|
memset(buffer, 0, sizeof(buffer));
|
||
|
|
|
||
|
|
if ( !SocketReady() || (recv(m_Socket, (char *) buffer, 74, 0) != 74) )
|
||
|
|
{
|
||
|
|
LogMessage("[%d] ERROR: DoClientKeyExchange recv\n", m_RecvThreadHandle);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Clear the buffer
|
||
|
|
memset(buffer, 0, WWRSA_BLOCK_SIZE - RC4_KEY_SIZE + sizeof(long));
|
||
|
|
|
||
|
|
// Put the length in front of the buffer
|
||
|
|
unsigned char *key = buffer + sizeof(long);
|
||
|
|
*((unsigned long *) buffer) = ntohl(WWRSA_BLOCK_SIZE);
|
||
|
|
|
||
|
|
// Copy the RC4 key to the bottom of the buffer
|
||
|
|
unsigned char *dest = &key[WWRSA_BLOCK_SIZE - 1];
|
||
|
|
unsigned char *src = rc4key;
|
||
|
|
for (i = 0; i < RC4_KEY_SIZE; i++) *dest-- = *src++;
|
||
|
|
|
||
|
|
// Encrypt the RC4 key
|
||
|
|
m_WestwoodRSA.Encrypt(key, WWRSA_BLOCK_SIZE, key);
|
||
|
|
|
||
|
|
// Send the encrypted RC4 key to the server
|
||
|
|
int length = WWRSA_BLOCK_SIZE + sizeof(long);
|
||
|
|
|
||
|
|
// Returns true if not socket error or timeout and buffer was completely sent
|
||
|
|
return bool( SocketReady() && (send(m_Socket, (char *) buffer, length, 0) == length) );
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Connection::RunKeyExchange()
|
||
|
|
{
|
||
|
|
if (m_ServerType == CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY || m_ServerType == CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Unencrypted TCP link\n", m_RecvThreadHandle);
|
||
|
|
}
|
||
|
|
else if (m_ServerType < CONNECTION_TYPE_MASTER_SERVER_TO_SECTOR_SERVER)
|
||
|
|
{
|
||
|
|
if (!DoKeyExchange())
|
||
|
|
{
|
||
|
|
m_ConnectionActive = false;
|
||
|
|
LogMessage("[%d] Client key exchange failed. Aborting.\n", m_RecvThreadHandle);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (!DoClientKeyExchange())
|
||
|
|
{
|
||
|
|
m_ConnectionActive = false;
|
||
|
|
LogMessage("[%d] Server/Server key exchange failed. Aborting.\n", m_RecvThreadHandle);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::SendResponse(short opcode, unsigned char *data, size_t length)
|
||
|
|
{
|
||
|
|
//if (!this) return;
|
||
|
|
|
||
|
|
if (m_ServerType == CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_AvatarID == 0)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Invalid attempt to send via TCP: Last Owner = %s\n", m_RecvThreadHandle, m_LastOwner);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
*((short *) &m_SendBuffer[0]) = (short) length + sizeof(long);
|
||
|
|
*((short *) &m_SendBuffer[2]) = opcode;
|
||
|
|
|
||
|
|
if ((length + 4) < MAX_BUFFER)
|
||
|
|
{
|
||
|
|
memcpy(m_SendBuffer + sizeof(long), data, length);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Message too long to send via Connection: opcode %04x length %d\n", m_RecvThreadHandle, opcode, length);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int bytes = length + sizeof(long);
|
||
|
|
|
||
|
|
if (m_PacketLoggingEnabled)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Sending %d bytes (unencrypted)\n", m_RecvThreadHandle, bytes);
|
||
|
|
DumpBuffer(m_SendBuffer, bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_ServerType != CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_ServerType != CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER)
|
||
|
|
{
|
||
|
|
m_CryptOut.RC4(m_SendBuffer, bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
Send(m_SendBuffer, bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef WIN32
|
||
|
|
UINT WINAPI Connection::SocketRecvThread(LPVOID Param)
|
||
|
|
#else
|
||
|
|
void* Connection::SocketRecvThread(void *Param)
|
||
|
|
#endif
|
||
|
|
{
|
||
|
|
Connection* p_this = reinterpret_cast<Connection*>( Param );
|
||
|
|
|
||
|
|
p_this->RunRecvThread();
|
||
|
|
|
||
|
|
#ifdef WIN32
|
||
|
|
return 1;
|
||
|
|
#else
|
||
|
|
return NULL;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::RunRecvThread()
|
||
|
|
{
|
||
|
|
bool isSocketReady = false; // Used for checking Socket state
|
||
|
|
int numretries = 0;
|
||
|
|
|
||
|
|
int received;
|
||
|
|
unsigned short bytes;
|
||
|
|
short opcode;
|
||
|
|
|
||
|
|
EnbTcpHeader header;
|
||
|
|
char *ptr_hdr = (char*)&header;
|
||
|
|
|
||
|
|
memset(&header, 0, sizeof(header));
|
||
|
|
|
||
|
|
while (!g_ServerShutdown && !m_TcpThreadTerminated)
|
||
|
|
{
|
||
|
|
while (m_TcpThreadRunning)
|
||
|
|
{
|
||
|
|
// Do the key exchange if it hasn't been done yet
|
||
|
|
if (!m_KeysExchanged)
|
||
|
|
{
|
||
|
|
if (!RunKeyExchange())
|
||
|
|
{
|
||
|
|
// Key Exchange failed.
|
||
|
|
KillConnection();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_KeysExchanged = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Main Loop
|
||
|
|
|
||
|
|
isSocketReady = SocketReady(1); // One Second Timeout
|
||
|
|
|
||
|
|
if ( isSocketReady && (recv(m_Socket, ptr_hdr, 4, 0) == 4) )
|
||
|
|
{
|
||
|
|
m_InactivityTimer = 0;
|
||
|
|
|
||
|
|
if (m_PacketLoggingEnabled)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Received 4 byte header (encrypted):\n", m_RecvThreadHandle);
|
||
|
|
DumpBuffer((unsigned char *) &header, 4);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_ServerType != CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_ServerType != CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER)
|
||
|
|
{
|
||
|
|
m_CryptIn.RC4((unsigned char *) &header, 4);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_PacketLoggingEnabled)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Received 4 byte header (decrypted):\n", m_RecvThreadHandle);
|
||
|
|
DumpBuffer((unsigned char *) &header, 4);
|
||
|
|
}
|
||
|
|
|
||
|
|
bytes = header.size - sizeof(EnbTcpHeader); // Bytes to fetch
|
||
|
|
opcode = header.opcode; // Opcode for this packet
|
||
|
|
|
||
|
|
// This buffer check MUST be in place
|
||
|
|
if ( (bytes > MAX_BUFFER) )
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Received packet with incorrect payload length: opcode = 0x%02x, length = %d. Aborting.\n", m_RecvThreadHandle, opcode, bytes);
|
||
|
|
|
||
|
|
KillConnection(); // We're not permitting a 2nd chance.
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
//LogMessage("Received packet: opcode = 0x%02x, length = %d\n", opcode, bytes);
|
||
|
|
|
||
|
|
received = recv(m_Socket, (char *) m_RecvBuffer, bytes, 0);
|
||
|
|
numretries = 0;
|
||
|
|
|
||
|
|
while ( received != bytes && // Did we fetch everything?
|
||
|
|
SocketReady() && // Can we still get more?
|
||
|
|
numretries < MAX_RETRIES && // Can we still retry to get more?
|
||
|
|
m_TcpThreadRunning ) // And we haven't been told to stop?
|
||
|
|
{
|
||
|
|
int rcv = recv(m_Socket, (char *) (m_RecvBuffer + received), bytes - received, 0);
|
||
|
|
if (rcv > 0)
|
||
|
|
{
|
||
|
|
received += rcv;
|
||
|
|
}
|
||
|
|
else break;
|
||
|
|
|
||
|
|
numretries++; // Prevent an infinite loop
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( received == bytes && m_TcpThreadRunning ) // We got the whole package and we haven't been told top stop
|
||
|
|
{
|
||
|
|
if (m_ServerType != CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_ServerType != CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER)
|
||
|
|
{
|
||
|
|
m_CryptIn.RC4(m_RecvBuffer, bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_PacketLoggingEnabled)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Received %d byte packet\n", m_RecvThreadHandle, received);
|
||
|
|
DumpBuffer(m_RecvBuffer,bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (m_ServerType)
|
||
|
|
{
|
||
|
|
case CONNECTION_TYPE_CLIENT_TO_GLOBAL_SERVER :
|
||
|
|
ProcessGlobalServerOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_CLIENT_TO_MASTER_SERVER :
|
||
|
|
ProcessMasterServerOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_CLIENT_TO_SECTOR_SERVER :
|
||
|
|
//ProcessSectorServerOpcode(opcode, bytes);
|
||
|
|
LogMessage("[%d] ERROR!!: Sector Server opcode received!\n", m_RecvThreadHandle);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_MASTER_SERVER_TO_SECTOR_SERVER :
|
||
|
|
ProcessMasterServerToSectorServerOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_SECTOR_SERVER_TO_SECTOR_SERVER :
|
||
|
|
ProcessSectorServerToSectorServerOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY:
|
||
|
|
ProcessProxyClientOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER:
|
||
|
|
ProcessProxyGlobalOpcode(opcode, bytes);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
LogMessage("[%d] ERROR: Unknown type of connection.\n", m_RecvThreadHandle);
|
||
|
|
m_TcpThreadRunning = false; // Shouldn't happen (but was able to with a buffer overflow).
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Error Stage
|
||
|
|
|
||
|
|
if (m_TcpThreadRunning) // We weren't told to stop, but never got our whole packet
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Error receiving TCP packet on port %d, got %d bytes, expecting %d -- aborting!\n", m_RecvThreadHandle,m_TcpPort, received, bytes);
|
||
|
|
if (received > 0 && g_Debug && received < 10000) DumpBuffer(m_RecvBuffer, received);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_TcpThreadRunning = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Check Connection Status
|
||
|
|
|
||
|
|
DWORD error = WSAGetLastError();
|
||
|
|
if ( !isSocketReady && error == 0 )
|
||
|
|
{
|
||
|
|
m_InactivityTimer++;
|
||
|
|
|
||
|
|
if ( (m_MaxInactivityTime > 0) && (m_InactivityTimer > m_MaxInactivityTime) )
|
||
|
|
{
|
||
|
|
LogMessage("[%d] TCP connection on port %d exceeded maximum inactivity. Aborting.\n", m_RecvThreadHandle, m_TcpPort);
|
||
|
|
|
||
|
|
m_TcpThreadRunning = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
switch (error)
|
||
|
|
{
|
||
|
|
case 0:
|
||
|
|
LogMessage("[%d] TCP connection on port %d gracefully closed\n", m_RecvThreadHandle, m_TcpPort);
|
||
|
|
break;
|
||
|
|
case WSAECONNRESET:
|
||
|
|
LogMessage("[%d] TCP connection on port %d was reset\n", m_RecvThreadHandle, m_TcpPort);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
LogMessage("[%d] TCP error on port %d (Error %d). Aborting.\n", m_RecvThreadHandle, m_TcpPort, error);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_TcpThreadRunning = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
KillConnection();
|
||
|
|
|
||
|
|
// m_TcpThreadRunning was set to false. Go to sleep...
|
||
|
|
#ifdef WIN32
|
||
|
|
SuspendThread(m_RecvThreadHandle);
|
||
|
|
#else
|
||
|
|
pthread_cond_wait(&m_RecvThreadCond, &m_RecvThreadMtx);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
m_TcpThreadTerminated = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Kills an active connection on the Socket, if any, and suspends the thread
|
||
|
|
void Connection::KillConnection()
|
||
|
|
{
|
||
|
|
m_Mutex.Lock();
|
||
|
|
|
||
|
|
if (m_ServerType == CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_AvatarID != 0)
|
||
|
|
{
|
||
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(m_AvatarID);
|
||
|
|
if (p)
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Emergency shutdown for TCP comms thread for '%s'\n", m_RecvThreadHandle, p->Name());
|
||
|
|
p->SetTCPLoginLink(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( m_Socket != INVALID_SOCKET )
|
||
|
|
{
|
||
|
|
LogMessage("[%d] Closing Socket on port %d\n", m_RecvThreadHandle, m_TcpPort);
|
||
|
|
|
||
|
|
shutdown(m_Socket, 2); // Important!
|
||
|
|
closesocket(m_Socket);
|
||
|
|
m_Socket = INVALID_SOCKET;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_SendQueue->ResetQueue();
|
||
|
|
|
||
|
|
// No longer active, not running, Keys invalidated
|
||
|
|
m_TcpThreadRunning = false;
|
||
|
|
m_ConnectionActive = false;
|
||
|
|
m_KeysExchanged = false;
|
||
|
|
m_AvatarID = 0;
|
||
|
|
|
||
|
|
m_Mutex.Unlock();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Connection::PulseConnectionOutput()
|
||
|
|
{
|
||
|
|
int length;
|
||
|
|
int cumulative = 0;
|
||
|
|
|
||
|
|
if (!m_ConnectionActive || !m_TcpThreadRunning) return;
|
||
|
|
|
||
|
|
while (m_SendQueue->CheckQueue((m_SendBuffer2+cumulative), &length, (SEND_BUFFER_SIZE - cumulative)) )
|
||
|
|
{
|
||
|
|
cumulative += length;
|
||
|
|
if (m_SendQueue->CheckNextQueueSize() >= (SEND_BUFFER_SIZE - cumulative))
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cumulative > 0)
|
||
|
|
{
|
||
|
|
send(m_Socket, (char *) m_SendBuffer2, cumulative, 0);
|
||
|
|
}
|
||
|
|
}
|