TCP cleanup, added basis of web interface

This commit is contained in:
KimLS
2017-01-08 19:00:39 -08:00
parent 08e72bbbdd
commit 124728e0c7
43 changed files with 690 additions and 6442 deletions
-60
View File
@@ -16,8 +16,6 @@ SET(common_sources
emu_legacy.cpp
emu_limits.cpp
emu_opcodes.cpp
emu_tcp_connection.cpp
emu_tcp_server.cpp
emu_versions.cpp
eqdb.cpp
eqdb_res.cpp
@@ -67,12 +65,9 @@ SET(common_sources
spdat.cpp
string_util.cpp
struct_strategy.cpp
tcp_connection.cpp
tcp_server.cpp
textures.cpp
timer.cpp
unix.cpp
worldconn.cpp
xml_parser.cpp
platform.cpp
event/event_loop.cpp
@@ -100,17 +95,6 @@ SET(common_sources
patches/titanium_limits.cpp
patches/uf.cpp
patches/uf_limits.cpp
SocketLib/Base64.cpp
SocketLib/File.cpp
SocketLib/HttpdCookies.cpp
SocketLib/HttpdForm.cpp
SocketLib/HttpdSocket.cpp
SocketLib/HTTPSocket.cpp
SocketLib/MemFile.cpp
SocketLib/Mime.cpp
SocketLib/Parse.cpp
SocketLib/socket_include.cpp
SocketLib/Utility.cpp
StackWalker/StackWalker.cpp
tinyxml/tinystr.cpp
tinyxml/tinyxml.cpp
@@ -138,8 +122,6 @@ SET(common_headers
emu_limits.h
emu_opcodes.h
emu_oplist.h
emu_tcp_connection.h
emu_tcp_server.h
emu_versions.h
eq_constants.h
eq_packet_structs.h
@@ -210,16 +192,12 @@ SET(common_headers
spdat.h
string_util.h
struct_strategy.h
tcp_basic_server.h
tcp_connection.h
tcp_server.h
textures.h
timer.h
types.h
unix.h
useperl.h
version.h
worldconn.h
xml_parser.h
zone_numbers.h
event/background_task.h
@@ -269,18 +247,6 @@ SET(common_headers
patches/uf_limits.h
patches/uf_ops.h
patches/uf_structs.h
SocketLib/Base64.h
SocketLib/File.h
SocketLib/HttpdCookies.h
SocketLib/HttpdForm.h
SocketLib/HttpdSocket.h
SocketLib/HTTPSocket.h
SocketLib/IFile.h
SocketLib/MemFile.h
SocketLib/Mime.h
SocketLib/Parse.h
SocketLib/socket_include.h
SocketLib/Utility.h
StackWalker/StackWalker.h
tinyxml/tinystr.h
tinyxml/tinyxml.h
@@ -374,32 +340,6 @@ SOURCE_GROUP(Patches FILES
patches/uf_limits.cpp
)
SOURCE_GROUP(SocketLib FILES
SocketLib/Base64.h
SocketLib/File.h
SocketLib/HttpdCookies.h
SocketLib/HttpdForm.h
SocketLib/HttpdSocket.h
SocketLib/HTTPSocket.h
SocketLib/IFile.h
SocketLib/MemFile.h
SocketLib/Mime.h
SocketLib/Parse.h
SocketLib/socket_include.h
SocketLib/Utility.h
SocketLib/Base64.cpp
SocketLib/File.cpp
SocketLib/HttpdCookies.cpp
SocketLib/HttpdForm.cpp
SocketLib/HttpdSocket.cpp
SocketLib/HTTPSocket.cpp
SocketLib/MemFile.cpp
SocketLib/Mime.cpp
SocketLib/Parse.cpp
SocketLib/socket_include.cpp
SocketLib/Utility.cpp
)
SOURCE_GROUP(StackWalker FILES
StackWalker/StackWalker.h
StackWalker/StackWalker.cpp
-818
View File
@@ -1,818 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
There are really two or three different objects shoe-hored into this
connection object. Sombody really needs to factor out the relay link
crap into its own subclass of this object, it will clean things up
tremendously.
*/
#include "../common/global_define.h"
#include <iostream>
#include <string.h>
#include "emu_tcp_connection.h"
#include "emu_tcp_server.h"
#include "../common/servertalk.h"
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#define MSG_NOSIGNAL 0
#endif
#define TCPN_DEBUG 0
#define TCPN_DEBUG_Console 0
#define TCPN_DEBUG_Memory 0
#define TCPN_LOG_PACKETS 0
#define TCPN_LOG_RAW_DATA_OUT 0
#define TCPN_LOG_RAW_DATA_IN 0
//server side case
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET in_socket, uint32 irIP, uint16 irPort, bool iOldFormat)
: TCPConnection(ID, in_socket, irIP, irPort),
keepalive_timer(SERVER_TIMEOUT),
timeout_timer(SERVER_TIMEOUT * 2)
{
id = 0;
Server = nullptr;
pOldFormat = iOldFormat;
#ifdef MINILOGIN
TCPMode = modePacket;
PacketMode = packetModeLogin;
#else
if (pOldFormat)
TCPMode = modePacket;
else
TCPMode = modeConsole;
PacketMode = packetModeZone;
#endif
RelayLink = 0;
RelayServer = false;
RelayCount = 0;
RemoteID = 0;
}
//client outgoing connection case (and client side relay)
EmuTCPConnection::EmuTCPConnection(bool iOldFormat, EmuTCPServer* iRelayServer, eTCPMode iMode)
: TCPConnection(),
keepalive_timer(SERVER_TIMEOUT),
timeout_timer(SERVER_TIMEOUT * 2)
{
Server = iRelayServer;
if (Server)
RelayServer = true;
else
RelayServer = false;
RelayLink = 0;
RelayCount = 0;
RemoteID = 0;
pOldFormat = iOldFormat;
TCPMode = iMode;
PacketMode = packetModeZone;
#if TCPN_DEBUG_Memory >= 7
std::cout << "Constructor #1 on outgoing TCP# " << GetID() << std::endl;
#endif
}
//server side relay case
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort)
: TCPConnection(ID, 0, irIP, irPort),
keepalive_timer(SERVER_TIMEOUT),
timeout_timer(SERVER_TIMEOUT * 2)
{
Server = iServer;
RelayLink = iRelayLink;
RelayServer = true;
RelayCount = 0;
RemoteID = iRemoteID;
pOldFormat = false;
ConnectionType = Incoming;
TCPMode = modePacket;
PacketMode = packetModeZone;
#if TCPN_DEBUG_Memory >= 7
std::cout << "Constructor #3 on outgoing TCP# " << GetID() << std::endl;
#endif
}
EmuTCPConnection::~EmuTCPConnection() {
//the queues free their content right now I believe.
}
EmuTCPNetPacket_Struct* EmuTCPConnection::MakePacket(ServerPacket* pack, uint32 iDestination) {
int32 size = sizeof(EmuTCPNetPacket_Struct) + pack->size;
if (pack->compressed) {
size += 4;
}
if (iDestination) {
size += 4;
}
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) new uchar[size];
tnps->size = size;
tnps->opcode = pack->opcode;
*((uint8*) &tnps->flags) = 0;
uchar* buffer = tnps->buffer;
if (pack->compressed) {
tnps->flags.compressed = 1;
*((int32*) buffer) = pack->InflatedSize;
buffer += 4;
}
if (iDestination) {
tnps->flags.destination = 1;
*((int32*) buffer) = iDestination;
buffer += 4;
}
memcpy(buffer, pack->pBuffer, pack->size);
return tnps;
}
SPackSendQueue* EmuTCPConnection::MakeOldPacket(ServerPacket* pack) {
SPackSendQueue* spsq = (SPackSendQueue*) new uchar[sizeof(SPackSendQueue) + pack->size + 4];
if (pack->pBuffer != 0 && pack->size != 0)
memcpy((char *) &spsq->buffer[4], (char *) pack->pBuffer, pack->size);
memcpy((char *) &spsq->buffer[0], (char *) &pack->opcode, 2);
spsq->size = pack->size+4;
memcpy((char *) &spsq->buffer[2], (char *) &spsq->size, 2);
return spsq;
}
bool EmuTCPConnection::SendPacket(ServerPacket* pack, uint32 iDestination) {
if (!Connected())
return false;
eTCPMode tmp = GetMode();
if (tmp != modePacket && tmp != modeTransition)
return false;
LockMutex lock(&MState);
if (RemoteID)
return RelayLink->SendPacket(pack, RemoteID);
else if (pOldFormat) {
#if TCPN_LOG_PACKETS >= 1
if (pack && pack->opcode != 0) {
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Logging outgoing TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
#if TCPN_LOG_PACKETS == 2
if (pack->size >= 32)
DumpPacket(pack->pBuffer, 32);
else
DumpPacket(pack);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket(pack);
#endif
}
#endif
SPackSendQueue* spsq = MakeOldPacket(pack);
ServerSendQueuePushEnd(spsq->buffer, spsq->size);
safe_delete_array(spsq);
}
else {
EmuTCPNetPacket_Struct* tnps = MakePacket(pack, iDestination);
if (tmp == modeTransition) {
InModeQueuePush(tnps);
}
else {
#if TCPN_LOG_PACKETS >= 1
if (pack && pack->opcode != 0) {
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Logging outgoing TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
#if TCPN_LOG_PACKETS == 2
if (pack->size >= 32)
DumpPacket(pack->pBuffer, 32);
else
DumpPacket(pack);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket(pack);
#endif
}
#endif
ServerSendQueuePushEnd((uchar**) &tnps, tnps->size);
}
}
return true;
}
bool EmuTCPConnection::SendPacket(EmuTCPNetPacket_Struct* tnps) {
if (RemoteID)
return false;
if (!Connected())
return false;
if (GetMode() != modePacket)
return false;
LockMutex lock(&MState);
eTCPMode tmp = GetMode();
if (tmp == modeTransition) {
EmuTCPNetPacket_Struct* tnps2 = (EmuTCPNetPacket_Struct*) new uchar[tnps->size];
memcpy(tnps2, tnps, tnps->size);
InModeQueuePush(tnps2);
return true;
}
#if TCPN_LOG_PACKETS >= 1
if (tnps && tnps->opcode != 0) {
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << tnps->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort();
if (pOldFormat)
std::cout << " (OldFormat)";
std::cout << std::endl;
#if TCPN_LOG_PACKETS == 2
if (tnps->size >= 32)
DumpPacket((uchar*) tnps, 32);
else
DumpPacket((uchar*) tnps, tnps->size);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket((uchar*) tnps, tnps->size);
#endif
}
#endif
ServerSendQueuePushEnd((const uchar*) tnps, tnps->size);
return true;
}
ServerPacket* EmuTCPConnection::PopPacket() {
ServerPacket* ret;
if (!MOutQueueLock.trylock())
return nullptr;
ret = OutQueue.pop();
MOutQueueLock.unlock();
return ret;
}
void EmuTCPConnection::InModeQueuePush(EmuTCPNetPacket_Struct* tnps) {
MSendQueue.lock();
InModeQueue.push(tnps);
MSendQueue.unlock();
}
void EmuTCPConnection::OutQueuePush(ServerPacket* pack) {
MOutQueueLock.lock();
OutQueue.push(pack);
MOutQueueLock.unlock();
}
bool EmuTCPConnection::LineOutQueuePush(char* line) {
#if defined(GOTFRAGS) && 0
if (strcmp(line, "**CRASHME**") == 0) {
int i = 0;
std::cout << (5 / i) << std::endl;
}
#endif
if(line[0] == '*') {
if (strcmp(line, "**PACKETMODE**") == 0) {
MSendQueue.lock();
safe_delete_array(sendbuf);
if (TCPMode == modeConsole)
Send((const uchar*) "\0**PACKETMODE**\r", 16);
TCPMode = modePacket;
PacketMode = packetModeLogin;
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop())) {
SendPacket(tnps);
safe_delete_array(tnps);
}
MSendQueue.unlock();
safe_delete_array(line);
return(true);
}
if (strcmp(line, "**PACKETMODEZONE**") == 0) {
MSendQueue.lock();
safe_delete_array(sendbuf);
if (TCPMode == modeConsole)
Send((const uchar*) "\0**PACKETMODEZONE**\r", 20);
TCPMode = modePacket;
PacketMode = packetModeZone;
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop())) {
SendPacket(tnps);
safe_delete_array(tnps);
}
MSendQueue.unlock();
safe_delete_array(line);
return(true);
}
if (strcmp(line, "**PACKETMODELAUNCHER**") == 0) {
MSendQueue.lock();
safe_delete_array(sendbuf);
if (TCPMode == modeConsole)
Send((const uchar*) "\0**PACKETMODELAUNCHER**\r", 24);
TCPMode = modePacket;
PacketMode = packetModeLauncher;
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop())) {
SendPacket(tnps);
safe_delete_array(tnps);
}
MSendQueue.unlock();
safe_delete_array(line);
return(true);
}
if (strcmp(line, "**PACKETMODEUCS**") == 0) {
MSendQueue.lock();
safe_delete_array(sendbuf);
if (TCPMode == modeConsole)
Send((const uchar*) "\0**PACKETMODEUCS**\r", 19);
TCPMode = modePacket;
PacketMode = packetModeUCS;
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop())) {
SendPacket(tnps);
safe_delete_array(tnps);
}
MSendQueue.unlock();
safe_delete_array(line);
return(true);
}
if (strcmp(line, "**PACKETMODEQS**") == 0) {
MSendQueue.lock();
safe_delete_array(sendbuf);
if (TCPMode == modeConsole)
Send((const uchar*) "\0**PACKETMODEQS**\r", 18);
TCPMode = modePacket;
PacketMode = packetModeQueryServ;
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop())) {
SendPacket(tnps);
safe_delete_array(tnps);
}
MSendQueue.unlock();
safe_delete_array(line);
return(true);
}
}
return(TCPConnection::LineOutQueuePush(line));
}
void EmuTCPConnection::Disconnect(bool iSendRelayDisconnect) {
TCPConnection::Disconnect();
if (RelayLink) {
RelayLink->RemoveRelay(this, iSendRelayDisconnect);
RelayLink = 0;
}
}
bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) {
if(!TCPConnection::ConnectIP(irIP, irPort, errbuf))
return(false);
MSendQueue.lock();
#ifdef MINILOGIN
TCPMode = modePacket;
#else
if (pOldFormat) {
TCPMode = modePacket;
}
else if (TCPMode == modePacket || TCPMode == modeTransition) {
TCPMode = modeTransition;
if(PacketMode == packetModeLauncher) {
safe_delete_array(sendbuf);
sendbuf_size = 24;
sendbuf_used = sendbuf_size;
sendbuf = new uchar[sendbuf_size];
memcpy(sendbuf, "\0**PACKETMODELAUNCHER**\r", sendbuf_size);
} else if(PacketMode == packetModeLogin) {
safe_delete_array(sendbuf);
sendbuf_size = 16;
sendbuf_used = sendbuf_size;
sendbuf = new uchar[sendbuf_size];
memcpy(sendbuf, "\0**PACKETMODE**\r", sendbuf_size);
} else if(PacketMode == packetModeUCS) {
safe_delete_array(sendbuf);
sendbuf_size = 19;
sendbuf_used = sendbuf_size;
sendbuf = new uchar[sendbuf_size];
memcpy(sendbuf, "\0**PACKETMODEUCS**\r", sendbuf_size);
}
else if(PacketMode == packetModeQueryServ) {
safe_delete_array(sendbuf);
sendbuf_size = 18;
sendbuf_used = sendbuf_size;
sendbuf = new uchar[sendbuf_size];
memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size);
}
else {
//default: packetModeZone
safe_delete_array(sendbuf);
sendbuf_size = 20;
sendbuf_used = sendbuf_size;
sendbuf = new uchar[sendbuf_size];
memcpy(sendbuf, "\0**PACKETMODEZONE**\r", sendbuf_size);
}
}
#endif
MSendQueue.unlock();
return(true);
}
void EmuTCPConnection::ClearBuffers() {
TCPConnection::ClearBuffers();
LockMutex lock2(&MOutQueueLock);
ServerPacket* pack = 0;
while ((pack = OutQueue.pop()))
safe_delete(pack);
EmuTCPNetPacket_Struct* tnps = 0;
while ((tnps = InModeQueue.pop()))
safe_delete(tnps);
keepalive_timer.Start();
timeout_timer.Start();
}
void EmuTCPConnection::SendNetErrorPacket(const char* reason) {
#if TCPC_DEBUG >= 1
struct in_addr in;
in.s_addr = GetrIP();
std::cout "NetError: '";
if (reason)
std::cout << reason;
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
#endif
auto pack = new ServerPacket(0);
pack->size = 1;
if (reason)
pack->size += strlen(reason) + 1;
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
pack->pBuffer[0] = 255;
strcpy((char *)&pack->pBuffer[1], reason);
SendPacket(pack);
safe_delete(pack);
}
void EmuTCPConnection::RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect) {
if (iSendRelayDisconnect) {
auto pack = new ServerPacket(0, 5);
pack->pBuffer[0] = 3;
*((uint32*) &pack->pBuffer[1]) = relay->GetRemoteID();
SendPacket(pack);
safe_delete(pack);
}
RelayCount--;
}
bool EmuTCPConnection::ProcessReceivedData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
timeout_timer.Start();
if (!recvbuf)
return true;
if (TCPMode == modePacket) {
if (pOldFormat)
return ProcessReceivedDataAsOldPackets(errbuf);
else
return ProcessReceivedDataAsPackets(errbuf);
}
//else, use the base class's text processing.
bool ret = TCPConnection::ProcessReceivedData(errbuf);
//see if we made the transition to packet mode...
if(ret && TCPMode == modePacket) {
return ProcessReceivedDataAsPackets(errbuf);
}
return(ret);
}
bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
int32 base = 0;
int32 size = 7;
uchar* buffer;
ServerPacket* pack = 0;
while ((recvbuf_used - base) >= size) {
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) &recvbuf[base];
buffer = tnps->buffer;
size = tnps->size;
if (size >= MaxTCPReceiveBuffferSize) {
#if TCPN_DEBUG_Memory >= 1
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
DumpPacket(&recvbuf[base], 16);
#endif
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
return false;
}
if ((recvbuf_used - base) >= size) {
// ok, we got enough data to make this packet!
pack = new ServerPacket;
pack->size = size - sizeof(EmuTCPNetPacket_Struct);
// read headers
pack->opcode = tnps->opcode;
if (tnps->flags.compressed) {
pack->compressed = true;
pack->InflatedSize = *((int32*)buffer);
pack->size -= 4;
buffer += 4;
}
if (tnps->flags.destination) {
pack->destination = *((int32*)buffer);
pack->size -= 4;
buffer += 4;
}
// end read headers
if (pack->size > 0) {
if (tnps->flags.compressed) {
// Lets decompress the packet here
pack->compressed = false;
pack->pBuffer = new uchar[pack->InflatedSize];
pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize);
}
else {
pack->pBuffer = new uchar[pack->size];
memcpy(pack->pBuffer, buffer, pack->size);
}
}
if (pack->opcode == 0) {
if (pack->size) {
#if TCPN_DEBUG >= 2
std::cout << "Received TCP Network layer packet" << std::endl;
#endif
ProcessNetworkLayerPacket(pack);
}
#if TCPN_DEBUG >= 5
else {
std::cout << "Received TCP keepalive packet. (opcode=0)" << std::endl;
}
#endif
// keepalive, no need to process
safe_delete(pack);
}
else {
#if TCPN_LOG_PACKETS >= 1
if (pack && pack->opcode != 0) {
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Logging incoming TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
#if TCPN_LOG_PACKETS == 2
if (pack->size >= 32)
DumpPacket(pack->pBuffer, 32);
else
DumpPacket(pack);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket(pack);
#endif
}
#endif
if (RelayServer && Server && pack->destination) {
EmuTCPConnection* con = Server->FindConnection(pack->destination);
if (!con) {
#if TCPN_DEBUG >= 1
std::cout << "Error relaying packet: con = 0" << std::endl;
#endif
safe_delete(pack);
}
else
con->OutQueuePush(pack);
}
else
OutQueuePush(pack);
}
base += size;
size = 7;
}
}
if (base != 0) {
if (base >= recvbuf_used) {
safe_delete_array(recvbuf);
} else {
auto tmpbuf = new uchar[recvbuf_size - base];
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
recvbuf_used -= base;
recvbuf_size -= base;
}
}
return true;
}
bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) {
int32 base = 0;
int32 size = 4;
uchar* buffer;
ServerPacket* pack = 0;
while ((recvbuf_used - base) >= size) {
buffer = &recvbuf[base];
memcpy(&size, &buffer[2], 2);
if (size >= MaxTCPReceiveBuffferSize) {
#if TCPN_DEBUG_Memory >= 1
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
#endif
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
return false;
}
if ((recvbuf_used - base) >= size) {
// ok, we got enough data to make this packet!
pack = new ServerPacket;
memcpy(&pack->opcode, &buffer[0], 2);
pack->size = size - 4;
/* if () { // TODO: Checksum or size check or something similar
// Datastream corruption, get the hell outta here!
delete pack;
return false;
}*/
if (pack->size > 0) {
pack->pBuffer = new uchar[pack->size];
memcpy(pack->pBuffer, &buffer[4], pack->size);
}
if (pack->opcode == 0) {
// keepalive, no need to process
safe_delete(pack);
}
else {
#if TCPN_LOG_PACKETS >= 1
if (pack && pack->opcode != 0) {
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
#if TCPN_LOG_PACKETS == 2
if (pack->size >= 32)
DumpPacket(pack->pBuffer, 32);
else
DumpPacket(pack);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket(pack);
#endif
}
#endif
OutQueuePush(pack);
}
base += size;
size = 4;
}
}
if (base != 0) {
if (base >= recvbuf_used) {
safe_delete_array(recvbuf);
}
else {
auto tmpbuf = new uchar[recvbuf_size - base];
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
recvbuf_used -= base;
recvbuf_size -= base;
}
}
return true;
}
void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
uint8 opcode = pack->pBuffer[0];
uint8* data = &pack->pBuffer[1];
switch (opcode) {
case 0: {
break;
}
case 1: { // Switch to RelayServer mode
if (pack->size != 1) {
SendNetErrorPacket("New RelayClient: wrong size, expected 1");
break;
}
if (RelayServer) {
SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode");
break;
}
if (RemoteID) {
SendNetErrorPacket("Switch to RelayServer mode by a Relay Client");
break;
}
if (ConnectionType != Incoming) {
SendNetErrorPacket("Switch to RelayServer mode on outgoing connection");
break;
}
#if TCPC_DEBUG >= 3
struct in_addr in;
in.s_addr = GetrIP();
std::cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << std::endl;
#endif
RelayServer = true;
break;
}
case 2: { // New Relay Client
if (!RelayServer) {
SendNetErrorPacket("New RelayClient when not in RelayServer mode");
break;
}
if (pack->size != 11) {
SendNetErrorPacket("New RelayClient: wrong size, expected 11");
break;
}
if (ConnectionType != Incoming) {
SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
break;
}
auto con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32 *)data),
*((uint32 *)&data[4]), *((uint16 *)&data[8]));
Server->AddConnection(con);
RelayCount++;
break;
}
case 3: { // Delete Relay Client
if (!RelayServer) {
SendNetErrorPacket("Delete RelayClient when not in RelayServer mode");
break;
}
if (pack->size != 5) {
SendNetErrorPacket("Delete RelayClient: wrong size, expected 5");
break;
}
EmuTCPConnection* con = Server->FindConnection(*((uint32*)data));
if (con) {
if (ConnectionType == Incoming) {
if (con->GetRelayLink() != this) {
SendNetErrorPacket("Delete RelayClient: RelayLink != this");
break;
}
}
con->Disconnect(false);
}
break;
}
case 255: {
#if TCPC_DEBUG >= 1
struct in_addr in;
in.s_addr = GetrIP();
std::cout "Received NetError: '";
if (pack->size > 1)
std::cout << (char*) data;
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
#endif
break;
}
}
}
bool EmuTCPConnection::SendData(bool &sent_something, char* errbuf) {
sent_something = false;
if(!TCPConnection::SendData(sent_something, errbuf))
return(false);
if(sent_something)
keepalive_timer.Start();
else if (TCPMode == modePacket && keepalive_timer.Check()) {
auto pack = new ServerPacket(0, 0);
SendPacket(pack);
safe_delete(pack);
#if TCPN_DEBUG >= 5
std::cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer.GetRemainingTime() << " remaining)" << std::endl;
#endif
}
return(true);
}
bool EmuTCPConnection::RecvData(char* errbuf) {
if(!TCPConnection::RecvData(errbuf)) {
if (OutQueue.count())
return(true);
else
return(false);
}
if ((TCPMode == modePacket || TCPMode == modeTransition) && timeout_timer.Check()) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection timeout");
return false;
}
return(true);
}
-104
View File
@@ -1,104 +0,0 @@
#ifndef EmuTCPCONNECTION_H_
#define EmuTCPCONNECTION_H_
#include "tcp_connection.h"
#include "timer.h"
//moved out of TCPConnection:: to be more exportable
#pragma pack(1)
struct EmuTCPNetPacket_Struct {
uint32 size;
struct {
uint8
compressed : 1,
destination : 1,
flag3 : 1,
flag4 : 1,
flag5 : 1,
flag6 : 1,
flag7 : 1,
flag8 : 1;
} flags;
uint16 opcode;
uchar buffer[0];
};
#pragma pack()
struct SPackSendQueue;
class EmuTCPServer;
class ServerPacket;
class EmuTCPConnection : public TCPConnection {
public:
enum eTCPMode { modeConsole, modeTransition, modePacket };
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort); // for relay connections
virtual ~EmuTCPConnection();
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
virtual void Disconnect(bool iSendRelayDisconnect = true);
static EmuTCPNetPacket_Struct* MakePacket(ServerPacket* pack, uint32 iDestination = 0);
static SPackSendQueue* MakeOldPacket(ServerPacket* pack);
virtual bool SendPacket(ServerPacket* pack, uint32 iDestination = 0);
virtual bool SendPacket(EmuTCPNetPacket_Struct* tnps);
ServerPacket* PopPacket(); // OutQueuePop()
void SetPacketMode(ePacketMode mode) { PacketMode = mode; }
eTCPMode GetMode() const { return TCPMode; }
ePacketMode GetPacketMode() const { return(PacketMode); }
//relay crap:
inline bool IsRelayServer() const { return RelayServer; }
inline TCPConnection* GetRelayLink() const { return RelayLink; }
inline uint32 GetRemoteID() const { return RemoteID; }
protected:
void OutQueuePush(ServerPacket* pack);
void RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect);
void SendNetErrorPacket(const char* reason = 0);
virtual bool SendData(bool &sent_something, char* errbuf = 0);
virtual bool RecvData(char* errbuf = 0);
virtual bool ProcessReceivedData(char* errbuf = 0);
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
void ProcessNetworkLayerPacket(ServerPacket* pack);
virtual bool LineOutQueuePush(char* line);
virtual void ClearBuffers();
EmuTCPServer* Server;
eTCPMode TCPMode;
ePacketMode PacketMode;
bool pOldFormat;
Timer keepalive_timer;
Timer timeout_timer;
//relay crap:
EmuTCPConnection* RelayLink;
int32 RelayCount;
bool RelayServer;
uint32 RemoteID;
//input queue...
void InModeQueuePush(EmuTCPNetPacket_Struct* tnps);
MyQueue<EmuTCPNetPacket_Struct> InModeQueue;
//output queue...
MyQueue<ServerPacket> OutQueue;
Mutex MOutQueueLock;
};
#endif /*EmuTCPCONNECTION_H_*/
-81
View File
@@ -1,81 +0,0 @@
#include "global_define.h"
#include "emu_tcp_server.h"
#include "emu_tcp_connection.h"
EmuTCPServer::EmuTCPServer(uint16 iPort, bool iOldFormat)
: TCPServer<EmuTCPConnection>(iPort),
pOldFormat(iOldFormat)
{
}
EmuTCPServer::~EmuTCPServer() {
MInQueue.lock();
while(!m_InQueue.empty()) {
delete m_InQueue.front();
m_InQueue.pop();
}
MInQueue.unlock();
}
void EmuTCPServer::Process() {
CheckInQueue();
TCPServer<EmuTCPConnection>::Process();
}
void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
{
auto conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat);
AddConnection(conn);
}
void EmuTCPServer::SendPacket(ServerPacket* pack) {
EmuTCPNetPacket_Struct* tnps = EmuTCPConnection::MakePacket(pack);
SendPacket(&tnps);
}
void EmuTCPServer::SendPacket(EmuTCPNetPacket_Struct** tnps) {
MInQueue.lock();
m_InQueue.push(*tnps);
MInQueue.unlock();
tnps = nullptr;
}
void EmuTCPServer::CheckInQueue() {
EmuTCPNetPacket_Struct* tnps = 0;
while (( tnps = InQueuePop() )) {
vitr cur, end;
cur = m_list.begin();
end = m_list.end();
for(; cur != end; cur++) {
if ((*cur)->GetMode() != EmuTCPConnection::modeConsole && (*cur)->GetRemoteID() == 0)
(*cur)->SendPacket(tnps);
}
safe_delete(tnps);
}
}
EmuTCPNetPacket_Struct* EmuTCPServer::InQueuePop() {
EmuTCPNetPacket_Struct* ret = nullptr;
MInQueue.lock();
if(!m_InQueue.empty()) {
ret = m_InQueue.front();
m_InQueue.pop();
}
MInQueue.unlock();
return ret;
}
EmuTCPConnection *EmuTCPServer::FindConnection(uint32 iID) {
vitr cur, end;
cur = m_list.begin();
end = m_list.end();
for(; cur != end; cur++) {
if ((*cur)->GetID() == iID)
return *cur;
}
return(nullptr);
}
-38
View File
@@ -1,38 +0,0 @@
#ifndef EmuTCPSERVER_H_
#define EmuTCPSERVER_H_
#include "tcp_server.h"
class EmuTCPConnection;
struct EmuTCPNetPacket_Struct;
class ServerPacket;
class EmuTCPServer : public TCPServer<EmuTCPConnection> {
public:
EmuTCPServer(uint16 iPort = 0, bool iOldFormat = false);
virtual ~EmuTCPServer();
//packet broadcast routines.
void SendPacket(ServerPacket* pack);
void SendPacket(EmuTCPNetPacket_Struct** tnps);
//special crap for relay management
EmuTCPConnection *FindConnection(uint32 iID);
//exposed for some crap we pull. Do not call from outside this object.
using TCPServer<EmuTCPConnection>::AddConnection;
protected:
virtual void Process();
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
bool pOldFormat;
//broadcast packet queue..
void CheckInQueue();
Mutex MInQueue;
EmuTCPNetPacket_Struct* InQueuePop(); //returns ownership
std::queue<EmuTCPNetPacket_Struct *> m_InQueue;
};
#endif /*EmuTCPSERVER_H_*/
+2 -2
View File
@@ -32,7 +32,6 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
out.PutUInt16(4, opcode);
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
(*(uint64_t*)&m_nonce_ours[0])++;
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
@@ -218,6 +217,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
{
Log.OutF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
@@ -235,7 +235,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
}
m_parent->ConnectionIdentified(this);
(*(uint64_t*)&m_nonce_theirs[0])++;
}
}
@@ -293,6 +292,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
if (m_encrypted) {
size_t message_len = length - crypto_secretbox_MACBYTES;
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
{
Log.OutF(Logs::General, Logs::Error, "Error decrypting message from client");
+2 -2
View File
@@ -62,7 +62,7 @@
#define ServerOP_ItemStatus 0x002C
#define ServerOP_OOCMute 0x002D
#define ServerOP_Revoke 0x002E
//#define 0x002F
#define ServerOP_WebInterfaceCall 0x002F
#define ServerOP_GroupIDReq 0x0030
#define ServerOP_GroupIDReply 0x0031
#define ServerOP_GroupLeave 0x0032 // for disbanding out of zone folks
@@ -227,7 +227,7 @@ public:
ServerPacket(uint16 in_opcode, const EQ::Net::Packet &p) {
this->compressed = false;
size = p.Length();
size = (uint32)p.Length();
opcode = in_opcode;
if (size == 0) {
pBuffer = 0;
-17
View File
@@ -1,17 +0,0 @@
#ifndef TCPBASICSERVER_H_
#define TCPBASICSERVER_H_
#include "tcp_server.h"
#include "tcp_connection.h"
class TCPBasicServer : public TCPServer<TCPConnection> {
public:
inline TCPBasicServer(uint16 iPort = 0) : TCPServer<TCPConnection>(iPort) { }
inline virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) {
TCPConnection *conn = new TCPConnection(ID, in_socket, irIP, irPort);
AddConnection(conn);
}
};
#endif /*TCPBASICSERVER_H_*/
-942
View File
@@ -1,942 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/global_define.h"
#include "../common/eqemu_logsys.h"
#include <iostream>
#include <string.h>
#include <iomanip>
#include "tcp_connection.h"
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#define MSG_NOSIGNAL 0
#endif
#ifdef DARWIN
#define MSG_NOSIGNAL SO_NOSIGPIPE // Corysia Taware - Sept. 27, 2013
// See http://lists.apple.com/archives/macnetworkprog/2002/Dec/msg00091.html
#endif // DARWIN
#ifdef _WINDOWS
InitWinsock winsock;
#endif
#define LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
#define TCPN_DEBUG 0
#define TCPN_DEBUG_Console 0
#define TCPN_DEBUG_Memory 0
#define TCPN_LOG_RAW_DATA_OUT 0 //1 = info, 2 = length limited dump, 3 = full dump
#define TCPN_LOG_RAW_DATA_IN 0 //1 = info, 2 = length limited dump, 3 = full dump
//client version
TCPConnection::TCPConnection()
: ConnectionType(Outgoing),
connection_socket(0),
id(0),
rIP(0),
rPort(0)
{
pState = TCPS_Ready;
pFree = false;
pEcho = false;
recvbuf = nullptr;
sendbuf = nullptr;
pRunLoop = false;
charAsyncConnect = 0;
pAsyncConnect = false;
m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
std::cout << "Constructor #2 on outgoing TCP# " << GetID() << std::endl;
#endif
}
//server version
TCPConnection::TCPConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
: ConnectionType(Incoming),
connection_socket(in_socket),
id(ID),
rIP(irIP),
rPort(irPort)
{
pState = TCPS_Connected;
pFree = false;
pEcho = false;
recvbuf = nullptr;
sendbuf = nullptr;
pRunLoop = false;
charAsyncConnect = 0;
pAsyncConnect = false;
m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
std::cout << "Constructor #2 on incoming TCP# " << GetID() << std::endl;
#endif
}
TCPConnection::~TCPConnection() {
FinishDisconnect();
ClearBuffers();
if (ConnectionType == Outgoing) {
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
MLoopRunning.lock();
MLoopRunning.unlock();
#if TCPN_DEBUG_Memory >= 6
std::cout << "Deconstructor on outgoing TCP# " << GetID() << std::endl;
#endif
}
#if TCPN_DEBUG_Memory >= 5
else {
std::cout << "Deconstructor on incoming TCP# " << GetID() << std::endl;
}
#endif
safe_delete_array(recvbuf);
safe_delete_array(sendbuf);
safe_delete_array(charAsyncConnect);
}
void TCPConnection::SetState(State_t in_state) {
MState.lock();
pState = in_state;
MState.unlock();
}
TCPConnection::State_t TCPConnection::GetState() const {
State_t ret;
MState.lock();
ret = pState;
MState.unlock();
return ret;
}
bool TCPConnection::GetSockName(char *host, uint16 *port)
{
bool result=false;
LockMutex lock(&MState);
if (!Connected())
return false;
struct sockaddr_in local;
#ifdef _WINDOWS
int addrlen;
#else
#ifdef FREEBSD
socklen_t addrlen;
#else
size_t addrlen;
#endif
#endif
addrlen=sizeof(struct sockaddr_in);
#ifdef _WINDOWS
if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
#else
if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
#endif
unsigned long ip=local.sin_addr.s_addr;
sprintf(host,"%d.%d.%d.%d",
*(unsigned char *)&ip,
*((unsigned char *)&ip+1),
*((unsigned char *)&ip+2),
*((unsigned char *)&ip+3));
*port=ntohs(local.sin_port);
result=true;
}
return result;
}
void TCPConnection::Free() {
Disconnect();
pFree = true;
}
bool TCPConnection::Send(const uchar* data, int32 size) {
if (!Connected())
return false;
if (!size)
return true;
ServerSendQueuePushEnd(data, size);
return true;
}
void TCPConnection::ServerSendQueuePushEnd(const uchar* data, int32 size) {
MSendQueue.lock();
if (sendbuf == nullptr) {
sendbuf = new uchar[size];
sendbuf_size = size;
sendbuf_used = 0;
}
else if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size + 1024;
auto tmp = new uchar[sendbuf_size];
memcpy(tmp, sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(&sendbuf[sendbuf_used], data, size);
sendbuf_used += size;
MSendQueue.unlock();
}
void TCPConnection::ServerSendQueuePushEnd(uchar** data, int32 size) {
MSendQueue.lock();
if (sendbuf == 0) {
sendbuf = *data;
sendbuf_size = size;
sendbuf_used = size;
MSendQueue.unlock();
*data = 0;
return;
}
if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size;
auto tmp = new uchar[sendbuf_size];
memcpy(tmp, sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(&sendbuf[sendbuf_used], *data, size);
sendbuf_used += size;
MSendQueue.unlock();
safe_delete_array(*data);
}
void TCPConnection::ServerSendQueuePushFront(uchar* data, int32 size) {
MSendQueue.lock();
if (sendbuf == 0) {
sendbuf = new uchar[size];
sendbuf_size = size;
sendbuf_used = 0;
}
else if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size;
auto tmp = new uchar[sendbuf_size];
memcpy(&tmp[size], sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(sendbuf, data, size);
sendbuf_used += size;
MSendQueue.unlock();
}
bool TCPConnection::ServerSendQueuePop(uchar** data, int32* size) {
bool ret;
if (!MSendQueue.trylock())
return false;
if (sendbuf) {
*data = sendbuf;
*size = sendbuf_used;
sendbuf = 0;
ret = true;
}
else {
ret = false;
}
MSendQueue.unlock();
return ret;
}
bool TCPConnection::ServerSendQueuePopForce(uchar** data, int32* size) {
bool ret;
MSendQueue.lock();
if (sendbuf) {
*data = sendbuf;
*size = sendbuf_used;
sendbuf = 0;
ret = true;
}
else {
ret = false;
}
MSendQueue.unlock();
return ret;
}
char* TCPConnection::PopLine() {
char* ret;
if (!MLineOutQueue.trylock())
return 0;
ret = (char*) LineOutQueue.pop();
MLineOutQueue.unlock();
return ret;
}
bool TCPConnection::LineOutQueuePush(char* line) {
MLineOutQueue.lock();
LineOutQueue.push(line);
MLineOutQueue.unlock();
return(false);
}
void TCPConnection::FinishDisconnect() {
MState.lock();
if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
bool sent_something = false;
SendData(sent_something);
}
pState = TCPS_Closing;
shutdown(connection_socket, 0x01);
shutdown(connection_socket, 0x00);
#ifdef _WINDOWS
closesocket(connection_socket);
#else
close(connection_socket);
#endif
connection_socket = 0;
rIP = 0;
rPort = 0;
ClearBuffers();
}
pState = TCPS_Disconnected;
MState.unlock();
}
void TCPConnection::Disconnect() {
MState.lock();
if(pState == TCPS_Connected || pState == TCPS_Connecting) {
pState = TCPS_Disconnecting;
}
MState.unlock();
}
bool TCPConnection::GetAsyncConnect() {
bool ret;
MAsyncConnect.lock();
ret = pAsyncConnect;
MAsyncConnect.unlock();
return ret;
}
bool TCPConnection::SetAsyncConnect(bool iValue) {
bool ret;
MAsyncConnect.lock();
ret = pAsyncConnect;
pAsyncConnect = iValue;
MAsyncConnect.unlock();
return ret;
}
bool TCPConnection::ConnectReady() const {
State_t s = GetState();
if (s != TCPS_Ready && s != TCPS_Disconnected)
return(false);
return(ConnectionType == Outgoing);
}
void TCPConnection::AsyncConnect(const char* irAddress, uint16 irPort) {
safe_delete_array(charAsyncConnect);
charAsyncConnect = new char[strlen(irAddress) + 1];
strcpy(charAsyncConnect, irAddress);
AsyncConnect((uint32) 0, irPort);
}
void TCPConnection::AsyncConnect(uint32 irIP, uint16 irPort) {
if (ConnectionType != Outgoing) {
// If this code runs, we got serious problems
// Crash and burn.
return;
}
if(!ConnectReady()) {
#if TCPN_DEBUG > 0
printf("Trying to do async connect in invalid state %s\n", GetState());
#endif
return;
}
MAsyncConnect.lock();
if (pAsyncConnect) {
MAsyncConnect.unlock();
#if TCPN_DEBUG > 0
printf("Trying to do async connect when already doing one.\n");
#endif
return;
}
#if TCPN_DEBUG > 0
printf("Start async connect.\n");
#endif
pAsyncConnect = true;
if(irIP != 0)
safe_delete_array(charAsyncConnect);
rIP = irIP;
rPort = irPort;
MAsyncConnect.unlock();
if (!pRunLoop) {
pRunLoop = true;
#ifdef _WINDOWS
_beginthread(TCPConnectionLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
#endif
}
return;
}
bool TCPConnection::Connect(const char* irAddress, uint16 irPort, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
uint32 tmpIP = ResolveIP(irAddress);
if (!tmpIP) {
if (errbuf) {
#ifdef _WINDOWS
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
#else
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
#endif
}
return false;
}
return ConnectIP(tmpIP, irPort, errbuf);
}
bool TCPConnection::ConnectIP(uint32 in_ip, uint16 in_port, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (ConnectionType != Outgoing) {
// If this code runs, we got serious problems
// Crash and burn.
return false;
}
MState.lock();
if (ConnectReady()) {
pState = TCPS_Connecting;
} else {
MState.unlock();
SetAsyncConnect(false);
return false;
}
MState.unlock();
if (!pRunLoop) {
pRunLoop = true;
#ifdef _WINDOWS
_beginthread(TCPConnectionLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
#endif
}
connection_socket = INVALID_SOCKET;
struct sockaddr_in server_sin;
//struct in_addr in;
if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
#ifdef _WINDOWS
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
#else
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
#endif
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
server_sin.sin_family = AF_INET;
server_sin.sin_addr.s_addr = in_ip;
server_sin.sin_port = htons(in_port);
// Establish a connection to the server socket.
#ifdef _WINDOWS
if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
closesocket(connection_socket);
connection_socket = 0;
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
#else
if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
close(connection_socket);
connection_socket = 0;
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
#endif
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef _WINDOWS
unsigned long nonblocking = 1;
ioctlsocket(connection_socket, FIONBIO, &nonblocking);
#else
fcntl(connection_socket, F_SETFL, O_NONBLOCK);
#endif
SetEcho(false);
ClearBuffers();
rIP = in_ip;
rPort = in_port;
SetState(TCPS_Connected);
SetAsyncConnect(false);
return true;
}
void TCPConnection::ClearBuffers() {
LockMutex lock1(&MSendQueue);
LockMutex lock3(&MRunLoop);
LockMutex lock4(&MState);
safe_delete_array(recvbuf);
safe_delete_array(sendbuf);
char* line = 0;
while ((line = LineOutQueue.pop()))
safe_delete_array(line);
}
bool TCPConnection::CheckNetActive() {
MState.lock();
if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
MState.unlock();
return true;
}
MState.unlock();
return false;
}
/* This is always called from an IO thread. Either the server socket's thread, or a
* special thread we create when we make an outbound connection. */
bool TCPConnection::Process() {
char errbuf[TCPConnection_ErrorBufferSize];
switch(GetState()) {
case TCPS_Ready:
case TCPS_Connecting:
if (ConnectionType == Outgoing) {
if (GetAsyncConnect()) {
if (charAsyncConnect)
rIP = ResolveIP(charAsyncConnect);
ConnectIP(rIP, rPort);
}
}
return(true);
case TCPS_Connected:
// only receive data in the connected state, no others...
if (!RecvData(errbuf)) {
struct in_addr in;
in.s_addr = GetrIP();
return false;
}
/* we break to do the send */
break;
case TCPS_Disconnecting: {
//waiting for any sending data to go out...
MSendQueue.lock();
if(sendbuf) {
if(sendbuf_used > 0) {
//something left to send, keep processing...
MSendQueue.unlock();
break;
}
//else, send buffer is empty.
safe_delete_array(sendbuf);
} //else, no send buffer, we are done.
MSendQueue.unlock();
}
/* Fallthrough */
case TCPS_Disconnected:
FinishDisconnect();
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
// SetState(TCPS_Ready); //reset the state in case they want to use it again...
return(false);
case TCPS_Closing:
//I dont understand this state...
case TCPS_Error:
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
return(false);
}
/* we get here in connected or disconnecting with more data to send */
bool sent_something = false;
if (!SendData(sent_something, errbuf)) {
struct in_addr in;
in.s_addr = GetrIP();
std::cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << std::endl;
return false;
}
return true;
}
bool TCPConnection::RecvData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (!Connected()) {
return false;
}
int status = 0;
if (recvbuf == 0) {
recvbuf = new uchar[5120];
recvbuf_size = 5120;
recvbuf_used = 0;
recvbuf_echo = 0;
}
else if ((recvbuf_size - recvbuf_used) < 2048) {
auto tmpbuf = new uchar[recvbuf_size + 5120];
memcpy(tmpbuf, recvbuf, recvbuf_used);
recvbuf_size += 5120;
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
return false;
}
}
status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);
if (status >= 1) {
#if TCPN_LOG_RAW_DATA_IN >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
std::cout << std::endl;
#if TCPN_LOG_RAW_DATA_IN == 2
int32 tmp = status;
if (tmp > 32)
tmp = 32;
DumpPacket(&recvbuf[recvbuf_used], status);
#elif TCPN_LOG_RAW_DATA_IN >= 3
DumpPacket(&recvbuf[recvbuf_used], status);
#endif
#endif
recvbuf_used += status;
if (!ProcessReceivedData(errbuf))
return false;
}
else if (status == SOCKET_ERROR) {
#ifdef _WINDOWS
if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
return false;
}
#else
if (!(errno == EWOULDBLOCK)) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
return false;
}
#endif
} else if (status == 0) {
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
return false;
}
return true;
}
bool TCPConnection::GetEcho() {
bool ret;
ret = pEcho;
return ret;
}
void TCPConnection::SetEcho(bool iValue) {
pEcho = iValue;
}
bool TCPConnection::ProcessReceivedData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (!recvbuf)
return true;
#if TCPN_DEBUG_Console >= 4
if (recvbuf_used) {
std::cout << "Starting Processing: recvbuf=" << recvbuf_used << std::endl;
DumpPacket(recvbuf, recvbuf_used);
}
#endif
for (int i=0; i < recvbuf_used; i++) {
if (GetEcho() && i >= recvbuf_echo) {
Send(&recvbuf[i], 1);
recvbuf_echo = i + 1;
}
switch(recvbuf[i]) {
case 0: { // 0 is the code for clear buffer
if (i==0) {
recvbuf_used--;
recvbuf_echo--;
memmove(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
if (i == recvbuf_used) {
safe_delete_array(recvbuf);
i = -1;
}
else {
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
recvbuf_used -= i + 1;
recvbuf_echo -= i + 1;
safe_delete_array(tmpdel);
i = -1;
}
}
#if TCPN_DEBUG_Console >= 5
std::cout << "Removed 0x00" << std::endl;
if (recvbuf_used) {
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
DumpPacket(recvbuf, recvbuf_used);
}
else
std::cout << "recbuf left: None" << std::endl;
#endif
m_previousLineEnd = false;
break;
}
case 10:
case 13: // newline marker
{
char *line = nullptr;
if (i==0) { // empty line
if(!m_previousLineEnd) {
//char right before this was NOT a CR, report the empty line.
line = new char[1];
line[0] = '\0';
m_previousLineEnd = true;
} else {
m_previousLineEnd = false;
}
recvbuf_used--;
recvbuf_echo--;
memcpy(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
line = new char[i+1];
memset(line, 0, i+1);
memcpy(line, recvbuf, i);
#if TCPN_DEBUG_Console >= 3
std::cout << "Line Out: " << std::endl;
DumpPacket((uchar*) line, i);
#endif
//line[i] = 0;
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
recvbuf_used -= i+1;
recvbuf_echo -= i+1;
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
#if TCPN_DEBUG_Console >= 5
std::cout << "i+1=" << i+1 << std::endl;
if (recvbuf_used) {
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
DumpPacket(recvbuf, recvbuf_used);
}
else
std::cout << "recbuf left: None" << std::endl;
#endif
safe_delete_array(tmpdel);
i = -1;
m_previousLineEnd = true;
}
if(line != nullptr) {
bool finish_proc = false;
finish_proc = LineOutQueuePush(line);
if(finish_proc)
return(true); //break early as requested by LineOutQueuePush
}
break;
}
case 8: // backspace
{
if (i==0) { // nothin to backspace
recvbuf_used--;
recvbuf_echo--;
memmove(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
memcpy(recvbuf, tmpdel, i-1);
memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
recvbuf_used -= 2;
recvbuf_echo -= 2;
safe_delete_array(tmpdel);
i -= 2;
}
break;
m_previousLineEnd = false;
}
default:
m_previousLineEnd = false;
}
}
if (recvbuf_used < 0)
safe_delete_array(recvbuf);
return true;
}
bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
/************ Get first send packet on queue and send it! ************/
uchar* data = 0;
int32 size = 0;
int status = 0;
if (ServerSendQueuePop(&data, &size)) {
#ifdef _WINDOWS
status = send(connection_socket, (const char *) data, size, 0);
#else
status = send(connection_socket, data, size, MSG_NOSIGNAL);
if(errno==EPIPE) status = SOCKET_ERROR;
#endif
if (status >= 1) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
std::cout << std::endl;
#if TCPN_LOG_RAW_DATA_OUT == 2
int32 tmp = status;
if (tmp > 32)
tmp = 32;
DumpPacket(data, status);
#elif TCPN_LOG_RAW_DATA_OUT >= 3
DumpPacket(data, status);
#endif
#endif
sent_something = true;
if (status < (signed)size) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
std::cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
std::cout << std::endl;
#endif
// If there's network congestion, the number of bytes sent can be less than
// what we tried to give it... Push the extra back on the queue for later
ServerSendQueuePushFront(&data[status], size - status);
}
else if (status > (signed)size) {
return false;
}
// else if (status == size) {}
}
else {
ServerSendQueuePushFront(data, size);
}
safe_delete_array(data);
if (status == SOCKET_ERROR) {
#ifdef _WINDOWS
if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EWOULDBLOCK)
#endif
{
if (errbuf) {
#ifdef _WINDOWS
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
#else
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
#endif
}
//if we get an error while disconnecting, just jump to disconnected
MState.lock();
if(pState == TCPS_Disconnecting)
pState = TCPS_Disconnected;
MState.unlock();
return false;
}
}
}
return true;
}
ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
#ifdef _WINDOWS
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
if (tmp == 0) {
THREAD_RETURN(nullptr);
}
TCPConnection* tcpc = (TCPConnection*) tmp;
#ifndef WIN32
Log.Out(Logs::Detail, Logs::TCP_Connection, "%s Starting TCPConnectionLoop with thread ID %d", __FUNCTION__, pthread_self());
#endif
tcpc->MLoopRunning.lock();
while (tcpc->RunLoop()) {
Sleep(LOOP_GRANULARITY);
if (!tcpc->ConnectReady()) {
if (!tcpc->Process()) {
//the processing loop has detecting an error..
//we want to drop the link immediately, so we clear buffers too.
tcpc->ClearBuffers();
tcpc->Disconnect();
}
Sleep(1);
}
else if (tcpc->GetAsyncConnect()) {
if (tcpc->charAsyncConnect)
tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
else
tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
tcpc->SetAsyncConnect(false);
}
else
Sleep(10); //nothing to do.
}
tcpc->MLoopRunning.unlock();
#ifndef WIN32
Log.Out(Logs::Detail, Logs::TCP_Connection, "%s Ending TCPConnectionLoop with thread ID %d", __FUNCTION__, pthread_self());
#endif
THREAD_RETURN(nullptr);
}
bool TCPConnection::RunLoop() {
bool ret;
MRunLoop.lock();
ret = pRunLoop;
MRunLoop.unlock();
return ret;
}
-176
View File
@@ -1,176 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TCP_CONNECTION_H
#define TCP_CONNECTION_H
/*
Parent classes for interserver TCP Communication.
-Quagmire
*/
#ifdef _WINDOWS
#if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900))
#define snprintf _snprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#include <process.h>
#else
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#include "unix.h"
#endif
#include "types.h"
#include "mutex.h"
#include "queue.h"
#include "misc_functions.h"
#define TCPConnection_ErrorBufferSize 1024
#define MaxTCPReceiveBuffferSize 524288
#ifndef DEF_eConnectionType
#define DEF_eConnectionType
enum eConnectionType {Incoming, Outgoing};
#endif
class TCPConnection {
protected:
typedef enum {
TCPS_Ready = 0,
TCPS_Connecting = 1,
TCPS_Connected = 100,
TCPS_Disconnecting = 200, //I do not know the difference between Disconnecting and Closing
TCPS_Disconnected = 201,
TCPS_Closing = 250,
TCPS_Error = 255
} State_t;
public:
//socket created by a server (incoming)
TCPConnection(uint32 ID, SOCKET iSock, uint32 irIP, uint16 irPort);
//socket created to connect to a server (outgoing)
TCPConnection(); // for outgoing connections
virtual ~TCPConnection();
// Functions for outgoing connections
bool Connect(const char* irAddress, uint16 irPort, char* errbuf = 0);
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
void AsyncConnect(const char* irAddress, uint16 irPort);
void AsyncConnect(uint32 irIP, uint16 irPort);
virtual void Disconnect();
bool Send(const uchar* data, int32 size);
char* PopLine(); //returns ownership of allocated byte array
inline uint32 GetrIP() const { return rIP; }
inline uint16 GetrPort() const { return rPort; }
virtual State_t GetState() const;
inline bool Connected() const { return (GetState() == TCPS_Connected); }
bool ConnectReady() const;
void Free(); // Inform TCPServer that this connection object is no longer referanced
inline uint32 GetID() const { return id; }
bool GetEcho();
void SetEcho(bool iValue);
bool GetSockName(char *host, uint16 *port);
//should only be used by TCPServer<T>:
bool CheckNetActive();
inline bool IsFree() const { return pFree; }
virtual bool Process();
protected:
friend class BaseTCPServer;
void SetState(State_t iState);
static ThreadReturnType TCPConnectionLoop(void* tmp);
// SOCKET sock;
bool RunLoop();
Mutex MLoopRunning;
Mutex MAsyncConnect;
bool GetAsyncConnect();
bool SetAsyncConnect(bool iValue);
char* charAsyncConnect;
bool pAsyncConnect; //this flag should really be turned into a state instead.
virtual bool ProcessReceivedData(char* errbuf = 0);
virtual bool SendData(bool &sent_something, char* errbuf = 0);
virtual bool RecvData(char* errbuf = 0);
virtual void ClearBuffers();
bool m_previousLineEnd;
eConnectionType ConnectionType;
Mutex MRunLoop;
bool pRunLoop;
SOCKET connection_socket;
uint32 id;
uint32 rIP;
uint16 rPort; // host byte order
bool pFree;
mutable Mutex MState;
State_t pState;
//text based line out queue.
Mutex MLineOutQueue;
virtual bool LineOutQueuePush(char* line); //this is really kinda a hack for the transition to packet mode. Returns true to stop processing the output.
MyQueue<char> LineOutQueue;
uchar* recvbuf;
int32 recvbuf_size;
int32 recvbuf_used;
int32 recvbuf_echo;
volatile bool pEcho;
Mutex MSendQueue;
uchar* sendbuf;
int32 sendbuf_size;
int32 sendbuf_used;
bool ServerSendQueuePop(uchar** data, int32* size);
bool ServerSendQueuePopForce(uchar** data, int32* size); //does a lock() instead of a trylock()
void ServerSendQueuePushEnd(const uchar* data, int32 size);
void ServerSendQueuePushEnd(uchar** data, int32 size);
void ServerSendQueuePushFront(uchar* data, int32 size);
private:
void FinishDisconnect();
};
#endif
-231
View File
@@ -1,231 +0,0 @@
#include "global_define.h"
#include "tcp_server.h"
#include "../common/eqemu_logsys.h"
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#ifdef _WINDOWS
#include <process.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#endif
#define SERVER_LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
BaseTCPServer::BaseTCPServer(uint16 in_port) {
NextID = 1;
pPort = in_port;
sock = 0;
pRunLoop = true;
#ifdef _WINDOWS
_beginthread(BaseTCPServer::TCPServerLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, nullptr, &BaseTCPServer::TCPServerLoop, this);
#endif
}
BaseTCPServer::~BaseTCPServer() {
StopLoopAndWait();
}
void BaseTCPServer::StopLoopAndWait() {
MRunLoop.lock();
if(pRunLoop) {
pRunLoop = false;
MRunLoop.unlock();
//wait for loop to stop.
MLoopRunning.lock();
MLoopRunning.unlock();
} else {
MRunLoop.unlock();
}
}
bool BaseTCPServer::RunLoop() {
bool ret;
MRunLoop.lock();
ret = pRunLoop;
MRunLoop.unlock();
return ret;
}
ThreadReturnType BaseTCPServer::TCPServerLoop(void* tmp) {
#ifdef _WINDOWS
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
if (tmp == 0) {
THREAD_RETURN(nullptr);
}
BaseTCPServer* tcps = (BaseTCPServer*) tmp;
#ifndef WIN32
Log.Out(Logs::Detail, Logs::None, "Starting TCPServerLoop with thread ID %d", pthread_self());
#endif
tcps->MLoopRunning.lock();
while (tcps->RunLoop()) {
Sleep(SERVER_LOOP_GRANULARITY);
tcps->Process();
}
tcps->MLoopRunning.unlock();
#ifndef WIN32
Log.Out(Logs::Detail, Logs::None, "Ending TCPServerLoop with thread ID %d", pthread_self());
#endif
THREAD_RETURN(nullptr);
}
void BaseTCPServer::Process() {
ListenNewConnections();
}
void BaseTCPServer::ListenNewConnections() {
SOCKET tmpsock;
struct sockaddr_in from;
struct in_addr in;
unsigned int fromlen;
unsigned short port;
from.sin_family = AF_INET;
fromlen = sizeof(from);
LockMutex lock(&MSock);
#ifndef DARWIN // Corysia - On OSX, 0 is a valid fd.
if (!sock)
return;
#else
if (sock == -1) return;
#endif
// Check for pending connects
#ifdef _WINDOWS
unsigned long nonblocking = 1;
while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) {
ioctlsocket (tmpsock, FIONBIO, &nonblocking);
#else
#ifdef __CYGWIN__
while ((tmpsock = accept(sock, (struct sockaddr *) &from, (int *) &fromlen)) != INVALID_SOCKET) {
#else
while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) {
#endif
fcntl(tmpsock, F_SETFL, O_NONBLOCK);
#endif
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
port = from.sin_port;
in.s_addr = from.sin_addr.s_addr;
// New TCP connection, this must consume the socket.
CreateNewConnection(GetNextID(), tmpsock, in.s_addr, ntohs(from.sin_port));
}
}
bool BaseTCPServer::Open(uint16 in_port, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
LockMutex lock(&MSock);
if (sock != 0) {
if (errbuf)
snprintf(errbuf, TCPServer_ErrorBufferSize, "Listening socket already open");
return false;
}
if (in_port != 0) {
pPort = in_port;
}
#ifdef _WINDOWS
SOCKADDR_IN address;
unsigned long nonblocking = 1;
#else
struct sockaddr_in address;
#endif
int reuse_addr = 1;
// Setup internet address information.
// This is used with the bind() call
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(pPort);
address.sin_addr.s_addr = htonl(INADDR_ANY);
// Setting up TCP port for new TCP connections
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
if (errbuf)
snprintf(errbuf, TCPServer_ErrorBufferSize, "socket(): INVALID_SOCKET");
return false;
}
// Quag: dont think following is good stuff for TCP, good for UDP
// Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart
// without waiting for conns in TIME_WAIT to die
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
#ifdef _WINDOWS
closesocket(sock);
#else
close(sock);
#endif
sock = 0;
if (errbuf)
sprintf(errbuf, "bind(): <0");
return false;
}
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef _WINDOWS
ioctlsocket (sock, FIONBIO, &nonblocking);
#else
fcntl(sock, F_SETFL, O_NONBLOCK);
#endif
if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
#ifdef _WINDOWS
closesocket(sock);
if (errbuf)
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError());
#else
close(sock);
if (errbuf)
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno));
#endif
sock = 0;
return false;
}
return true;
}
void BaseTCPServer::Close() {
StopLoopAndWait();
LockMutex lock(&MSock);
if (sock) {
#ifdef _WINDOWS
closesocket(sock);
#else
close(sock);
#endif
}
sock = 0;
}
bool BaseTCPServer::IsOpen() {
MSock.lock();
bool ret = (bool) (sock != 0);
MSock.unlock();
return ret;
}
-135
View File
@@ -1,135 +0,0 @@
#ifndef TCPSERVER_H_
#define TCPSERVER_H_
#include "types.h"
#include "mutex.h"
#include <vector>
#include <queue>
#define TCPServer_ErrorBufferSize 1024
//this is the non-connection type specific server.
class BaseTCPServer {
public:
BaseTCPServer(uint16 iPort = 0);
virtual ~BaseTCPServer();
bool Open(uint16 iPort = 0, char* errbuf = 0); // opens the port
void Close(); // closes the port
bool IsOpen();
inline uint16 GetPort() { return pPort; }
inline uint32 GetNextID() { return NextID++; }
protected:
static ThreadReturnType TCPServerLoop(void* tmp);
//factory method:
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) = 0;
virtual void Process();
bool RunLoop();
Mutex MLoopRunning;
void StopLoopAndWait();
void ListenNewConnections();
uint32 NextID;
Mutex MRunLoop;
bool pRunLoop;
Mutex MSock;
SOCKET sock;
uint16 pPort;
};
template<class T>
class TCPServer : public BaseTCPServer {
protected:
typedef typename std::vector<T *> vstore;
typedef typename std::vector<T *>::iterator vitr;
public:
TCPServer(uint16 iPort = 0)
: BaseTCPServer(iPort) {
}
virtual ~TCPServer() {
StopLoopAndWait();
//im not sure what the right thing to do here is...
//we are freeing a connection which somebody likely has a pointer to..
//but, we really shouldent ever get called anyhow..
vitr cur, end;
cur = m_list.begin();
end = m_list.end();
for(; cur != end; ++cur) {
delete *cur;
}
}
T * NewQueuePop() {
T * ret = nullptr;
MNewQueue.lock();
if(!m_NewQueue.empty()) {
ret = m_NewQueue.front();
m_NewQueue.pop();
}
MNewQueue.unlock();
return ret;
}
protected:
virtual void Process() {
BaseTCPServer::Process();
vitr cur;
cur = m_list.begin();
while(cur != m_list.end()) {
T *data = *cur;
if (data->IsFree() && (!data->CheckNetActive())) {
#if EQN_DEBUG >= 4
std::cout << "TCPConnection Connection deleted." << std::endl;
#endif
delete data;
cur = m_list.erase(cur);
} else {
if (!data->Process())
data->Disconnect();
++cur;
}
}
}
void AddConnection(T *con) {
m_list.push_back(con);
MNewQueue.lock();
m_NewQueue.push(con);
MNewQueue.unlock();
}
//queue of new connections, for the app to pull from
Mutex MNewQueue;
std::queue<T *> m_NewQueue;
vstore m_list;
};
#endif /*TCPSERVER_H_*/
-87
View File
@@ -1,87 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/global_define.h"
#include "../common/eqemu_logsys.h"
#include <iomanip>
#include "worldconn.h"
#include "eqemu_config.h"
#include "md5.h"
#include "servertalk.h"
WorldConnection::WorldConnection(EmuTCPConnection::ePacketMode mode, const char *password)
: m_password(password)
{
tcpc.SetPacketMode(mode);
pTryReconnect = true;
pConnected = false;
}
WorldConnection::~WorldConnection() {
}
bool WorldConnection::SendPacket(ServerPacket* pack) {
if (!Connected())
return false;
return tcpc.SendPacket(pack);
}
void WorldConnection::OnConnected() {
const EQEmuConfig *Config=EQEmuConfig::get();
Log.Out(Logs::General, Logs::Netcode, "[WORLD] Connected to World: %s:%d", Config->WorldIP.c_str(), Config->WorldTCPPort);
auto pack = new ServerPacket(ServerOP_ZAAuth, 16);
MD5::Generate((const uchar*) m_password.c_str(), m_password.length(), pack->pBuffer);
SendPacket(pack);
safe_delete(pack);
}
void WorldConnection::Process() {
//persistent connection....
if (!Connected()) {
pConnected = tcpc.Connected();
if (pConnected) {
OnConnected();
}
else
return;
}
}
void WorldConnection::AsyncConnect() {
const EQEmuConfig *Config=EQEmuConfig::get();
tcpc.AsyncConnect(Config->WorldIP.c_str(), Config->WorldTCPPort);
}
bool WorldConnection::Connect() {
const EQEmuConfig *Config=EQEmuConfig::get();
char errbuf[TCPConnection_ErrorBufferSize];
if (tcpc.Connect(Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf)) {
return true;
} else {
Log.Out(Logs::General, Logs::Netcode, "[WORLD] WorldConnection connect: Connecting to the server %s:%d failed: %s", Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf);
}
return false;
}
void WorldConnection::Disconnect() {
tcpc.Disconnect();
}
-59
View File
@@ -1,59 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WORLDCONNECTION_H
#define WORLDCONNECTION_H
#include "../common/emu_tcp_connection.h"
#include <string>
class ServerPacket;
/*
* This object is an arbitrary connection to world.
*/
class WorldConnection {
public:
WorldConnection(EmuTCPConnection::ePacketMode mode, const char *password = "");
virtual ~WorldConnection();
virtual void Process();
bool SendPacket(ServerPacket* pack);
uint32 GetIP() const { return tcpc.GetrIP(); }
uint16 GetPort() const { return tcpc.GetrPort(); }
bool Connected() const { return (pConnected && tcpc.Connected()); }
void SetPassword(const char *password) { m_password = password; }
bool Connect();
void AsyncConnect();
void Disconnect();
inline bool TryReconnect() const { return pTryReconnect; }
protected:
virtual void OnConnected();
std::string m_password;
EmuTCPConnection tcpc;
bool pTryReconnect;
bool pConnected;
};
#endif