/* * Copyright (C) 2005-2008 MaNGOS * * Copyright (C) 2008 Trinity * * 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; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** \addtogroup u2w User to World Communication * @{ * \file WorldSocket.h * \author Derex */ #ifndef _WORLDSOCKET_H #define _WORLDSOCKET_H #include #include #include #include #include #include #include #include #include #include #if !defined (ACE_LACKS_PRAGMA_ONCE) #pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "Common.h" #include "Auth/AuthCrypt.h" class ACE_Message_Block; class WorldPacket; class WorldSession; /// Handler that can communicate over stream sockets. typedef ACE_Svc_Handler WorldHandler; /** * WorldSocket. * * This class is responsible for the communication with * remote clients. * Most methods return -1 on failure. * The class uses reference counting. * * For output the class uses one buffer (64K usually) and * a queue where it stores packet if there is no place on * the queue. The reason this is done, is because the server * does really a lot of small-size writes to it, and it doesn't * scale well to allocate memory for every. When something is * written to the output buffer the socket is not immediately * activated for output (again for the same reason), there * is 10ms celling (thats why there is Update() method). * This concept is similar to TCP_CORK, but TCP_CORK * uses 200ms celling. As result overhead generated by * sending packets from "producer" threads is minimal, * and doing a lot of writes with small size is tolerated. * * The calls to Update () method are managed by WorldSocketMgr * and ReactorRunnable. * * For input ,the class uses one 1024 bytes buffer on stack * to which it does recv() calls. And then received data is * distributed where its needed. 1024 matches pretty well the * traffic generated by client for now. * * The input/output do speculative reads/writes (AKA it tryes * to read all data available in the kernel buffer or tryes to * write everything available in userspace buffer), * which is ok for using with Level and Edge Triggered IO * notification. * */ class WorldSocket : protected WorldHandler { public: /// Declare some friends friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; friend class WorldSocketMgr; friend class ReactorRunnable; /// Declare the acceptor for this class typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; /// Mutex type used for various synchronizations. typedef ACE_Thread_Mutex LockType; typedef ACE_Guard GuardType; /// Queue for storing packets for which there is no space. typedef ACE_Unbounded_Queue< WorldPacket* > PacketQueueT; /// Check if socket is closed. bool IsClosed (void) const; /// Close the socket. void CloseSocket (void); /// Get address of connected peer. const std::string& GetRemoteAddress (void) const; /// Send A packet on the socket, this function is reentrant. /// @param pct packet to send /// @return -1 of failure int SendPacket (const WorldPacket& pct); /// Add reference to this object. long AddReference (void); /// Remove reference to this object. long RemoveReference (void); protected: /// things called by ACE framework. WorldSocket (void); virtual ~WorldSocket (void); /// Called on open ,the void* is the acceptor. virtual int open (void *); /// Called on failures inside of the acceptor, don't call from your code. virtual int close (int); /// Called when we can read from the socket. virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); /// Called when the socket can write. virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); /// Called when connection is closed or error happens. virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); /// Called by WorldSocketMgr/ReactorRunnable. int Update (void); private: /// Helper functions for processing incoming data. int handle_input_header (void); int handle_input_payload (void); int handle_input_missing_data (void); /// Help functions to mark/unmark the socket for output. /// @param g the guard is for m_OutBufferLock, the function will release it int cancel_wakeup_output (GuardType& g); int schedule_wakeup_output (GuardType& g); /// process one incoming packet. /// @param new_pct received packet ,note that you need to delete it. int ProcessIncoming (WorldPacket* new_pct); /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. int HandleAuthSession (WorldPacket& recvPacket); /// Called by ProcessIncoming() on CMSG_PING. int HandlePing (WorldPacket& recvPacket); /// Try to write WorldPacket to m_OutBuffer ,return -1 if no space /// Need to be called with m_OutBufferLock lock held int iSendPacket (const WorldPacket& pct); /// Flush m_PacketQueue if there are packets in it /// Need to be called with m_OutBufferLock lock held /// @return true if it wrote to the buffer ( AKA you need /// to mark the socket for output ). bool iFlushPacketQueue (); private: /// Time in which the last ping was received ACE_Time_Value m_LastPingTime; /// Keep track of over-speed pings ,to prevent ping flood. uint32 m_OverSpeedPings; /// Address of the remote peer std::string m_Address; /// Class used for managing encryption of the headers AuthCrypt m_Crypt; /// Mutex lock to protect m_Session LockType m_SessionLock; /// Session to which received packets are routed WorldSession* m_Session; /// here are stored the fragments of the received data WorldPacket* m_RecvWPct; /// This block actually refers to m_RecvWPct contents, /// which allows easy and safe writing to it. /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. ACE_Message_Block m_RecvPct; /// Fragment of the received header. ACE_Message_Block m_Header; /// Mutex for protecting output related data. LockType m_OutBufferLock; /// Buffer used for writing output. ACE_Message_Block *m_OutBuffer; /// Size of the m_OutBuffer. size_t m_OutBufferSize; /// Here are stored packets for which there was no space on m_OutBuffer, /// this allows not-to kick player if its buffer is overflowed. PacketQueueT m_PacketQueue; /// True if the socket is registered with the reactor for output bool m_OutActive; uint32 m_Seed; }; #endif /* _WORLDSOCKET_H */ /// @}