/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see .
*/
#ifndef TCP_CONNECTION_H
#define TCP_CONNECTION_H
/*
Parent classes for interserver TCP Communication.
-Quagmire
*/
#ifdef WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#include
#else
#include
#include
#include
#include
#include
#include
#include
#include
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#include "unix.h"
#endif
#include "types.h"
#include "Mutex.h"
#include "linked_list.h"
#include "queue.h"
#include "servertalk.h"
#include "timer.h"
#include "MiscFunctions.h"
class TCPServer;
#define TCPConnection_ErrorBufferSize 1024
#define MaxTCPReceiveBufferSize 524288
#define TCPS_Ready 0
#define TCPS_Connecting 1
#define TCPS_Connected 100
#define TCPS_Disconnecting 200
#define TCPS_Disconnected 201
#define TCPS_Closing 250
#define TCPS_Error 255
#ifndef DEF_eConnectionType
#define DEF_eConnectionType
enum eConnectionType {Incomming, Outgoing};
#endif
#ifdef WIN32
void TCPServerLoop(void* tmp);
void TCPConnectionLoop(void* tmp);
#else
void* TCPServerLoop(void* tmp);
void* TCPConnectionLoop(void* tmp);
#endif
enum eTCPMode { modeConsole, modeTransition, modePacket };
class TCPConnection {
public:
#pragma pack(1)
struct TCPNetPacket_Struct {
int32 size;
struct {
int8
compressed : 1,
destination : 1,
flag3 : 1,
flag4 : 1,
flag5 : 1,
flag6 : 1,
flag7 : 1,
flag8 : 1;
} flags;
int16 opcode;
uchar buffer[0];
};
#pragma pack()
static TCPNetPacket_Struct* MakePacket(ServerPacket* pack, int32 iDestination = 0);
TCPConnection(TCPServer* iServer, SOCKET iSock, int32 irIP, int16 irPort, bool iOldFormat = false);
TCPConnection(bool iOldFormat = false, TCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
TCPConnection(TCPServer* iServer, TCPConnection* iRelayLink, int32 iRemoteID, int32 irIP, int16 irPort); // for relay connections
virtual ~TCPConnection();
// Functions for outgoing connections
bool Connect(char* irAddress, int16 irPort, char* errbuf = 0);
bool Connect(int32 irIP, int16 irPort, char* errbuf = 0);
void AsyncConnect(char* irAddress, int16 irPort);
void AsyncConnect(int32 irIP, int16 irPort);
virtual void Disconnect(bool iSendRelayDisconnect = true);
virtual bool SendPacket(ServerPacket* pack, int32 iDestination = 0);
virtual bool SendPacket(TCPNetPacket_Struct* tnps);
bool Send(const uchar* data, sint32 size);
char* PopLine();
ServerPacket* PopPacket(); // OutQueuePop()
inline int32 GetrIP() { return rIP; }
inline int16 GetrPort() { return rPort; }
virtual int8 GetState();
eTCPMode GetMode() { return TCPMode; }
inline bool Connected() { return (GetState() == TCPS_Connected); }
inline bool ConnectReady() { return (bool) (GetState() == TCPS_Ready && ConnectionType == Outgoing); }
void Free(); // Inform TCPServer that this connection object is no longer referanced
inline int32 GetID() { return id; }
inline bool IsRelayServer() { return RelayServer; }
inline int32 GetRemoteID() { return RemoteID; }
inline TCPConnection* GetRelayLink() { return RelayLink; }
bool GetEcho();
void SetEcho(bool iValue);
protected:
friend class TCPServer;
virtual bool Process();
void SetState(int8 iState);
inline bool IsFree() { return pFree; }
bool CheckNetActive();
#ifdef WIN32
friend void TCPConnectionLoop(void* tmp);
#else
friend void* TCPConnectionLoop(void* tmp);
#endif
SOCKET sock;
bool RunLoop();
Mutex MLoopRunning;
Mutex MAsyncConnect;
bool GetAsyncConnect();
bool SetAsyncConnect(bool iValue);
char* charAsyncConnect;
#ifdef WIN32
friend class TCPConnection;
#endif
void OutQueuePush(ServerPacket* pack);
void RemoveRelay(TCPConnection* relay, bool iSendRelayDisconnect);
private:
void ProcessNetworkLayerPacket(ServerPacket* pack);
void SendNetErrorPacket(const char* reason = 0);
TCPServer* Server;
TCPConnection* RelayLink;
int32 RemoteID;
sint32 RelayCount;
bool pOldFormat;
bool SendData(char* errbuf = 0);
bool RecvData(char* errbuf = 0);
bool ProcessReceivedData(char* errbuf = 0);
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
void ClearBuffers();
bool pAsyncConnect;
eConnectionType ConnectionType;
eTCPMode TCPMode;
bool RelayServer;
Mutex MRunLoop;
bool pRunLoop;
SOCKET connection_socket;
int32 id;
int32 rIP;
int16 rPort; // host byte order
bool pFree;
Mutex MState;
int8 pState;
void LineOutQueuePush(char* line);
MyQueue LineOutQueue;
MyQueue OutQueue;
Mutex MOutQueueLock;
Timer* keepalive_timer;
Timer* timeout_timer;
uchar* recvbuf;
sint32 recvbuf_size;
sint32 recvbuf_used;
sint32 recvbuf_echo;
bool pEcho;
Mutex MEcho;
void InModeQueuePush(TCPNetPacket_Struct* tnps);
MyQueue InModeQueue;
Mutex MSendQueue;
uchar* sendbuf;
sint32 sendbuf_size;
sint32 sendbuf_used;
bool ServerSendQueuePop(uchar** data, sint32* size);
void ServerSendQueuePushEnd(const uchar* data, sint32 size);
void ServerSendQueuePushEnd(uchar** data, sint32 size);
void ServerSendQueuePushFront(uchar* data, sint32 size);
};
class TCPServer {
public:
TCPServer(int16 iPort = 0, bool iOldFormat = false);
virtual ~TCPServer();
bool Open(int16 iPort = 0, char* errbuf = 0); // opens the port
void Close(); // closes the port
bool IsOpen();
inline int16 GetPort() { return pPort; }
TCPConnection* NewQueuePop();
void SendPacket(ServerPacket* pack);
void SendPacket(TCPConnection::TCPNetPacket_Struct** tnps);
protected:
#ifdef WIN32
friend void TCPServerLoop(void* tmp);
#else
friend void* TCPServerLoop(void* tmp);
#endif
void Process();
bool RunLoop();
Mutex MLoopRunning;
friend class TCPConnection;
inline int32 GetNextID() { return NextID++; }
void AddConnection(TCPConnection* con);
TCPConnection* GetConnection(int32 iID);
private:
void ListenNewConnections();
int32 NextID;
bool pOldFormat;
Mutex MRunLoop;
bool pRunLoop;
Mutex MSock;
SOCKET sock;
int16 pPort;
Mutex MNewQueue;
MyQueue NewQueue;
void CheckInQueue();
Mutex MInQueue;
TCPConnection::TCPNetPacket_Struct* InQueuePop();
MyQueue InQueue;
LinkedList* list;
};
#endif