/* 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