2013-11-29 13:18:48 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2013-11-29 13:18:48 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2013-11-29 13:18:48 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2013-11-29 13:18:48 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2013-11-29 13:18:48 +00:00
*/
# ifndef INC_C4Network2IO
# define INC_C4Network2IO
2016-04-03 18:07:56 +00:00
# include "network/C4NetIO.h"
# include "network/C4Client.h"
# include "network/C4InteractiveThread.h"
2016-10-20 19:14:08 +00:00
# include "netpuncher/C4PuncherPacket.h"
2013-11-29 13:18:48 +00:00
class C4Network2IOConnection ;
// enums & constants
enum C4Network2IOProtocol
{
P_UDP , P_TCP , P_NONE = - 1
} ;
const int C4NetTimer = 500 , // ms
C4NetPingFreq = 1000 , // ms
C4NetStatisticsFreq = 1000 , // ms
C4NetAcceptTimeout = 10 , // s
C4NetPingTimeout = 30000 ; // ms
// client count
const int C4NetMaxClients = 256 ;
class C4Network2IO
: protected C4InteractiveThread : : Callback ,
protected C4NetIO : : CBClass ,
protected StdSchedulerProc
{
public :
C4Network2IO ( ) ;
virtual ~ C4Network2IO ( ) ;
protected :
// main traffic net i/o classes
C4NetIO * pNetIO_TCP , * pNetIO_UDP ;
// discovery net i/o
class C4Network2IODiscover * pNetIODiscover ;
// reference server
class C4Network2RefServer * pRefServer ;
// UPnP port mapping manager
class C4Network2UPnP * UPnPMgr ;
// local client core
C4ClientCore LCCore ;
CStdCSec LCCoreCSec ;
// connection list
C4Network2IOConnection * pConnList ;
CStdCSec ConnListCSec , BroadcastCSec ;
// next connection ID to use
uint32_t iNextConnID ;
// allow incoming connections?
bool fAllowConnect ;
// connection acceptance
struct AutoAccept
{
C4ClientCore CCore ;
AutoAccept * Next ;
}
* pAutoAcceptList ;
CStdCSec AutoAcceptCSec ;
// make sure only one connection is established?
bool fExclusiveConn ;
// timer & ping
2013-12-04 12:35:07 +00:00
C4TimeMilliseconds tLastExecute ;
C4TimeMilliseconds tLastPing ;
2013-11-29 13:18:48 +00:00
// statistics
2013-12-04 12:35:07 +00:00
C4TimeMilliseconds tLastStatistic ;
2013-11-29 13:18:48 +00:00
int iTCPIRate , iTCPORate , iTCPBCRate ,
iUDPIRate , iUDPORate , iUDPBCRate ;
2016-09-07 21:46:22 +00:00
// punching
2017-01-08 17:34:26 +00:00
C4NetIO : : addr_t PuncherAddrIPv4 , PuncherAddrIPv6 ;
bool IsPuncherAddr ( const C4NetIO : : addr_t & addr ) const ;
2016-09-07 21:46:22 +00:00
2013-11-29 13:18:48 +00:00
public :
bool hasTCP ( ) const { return ! ! pNetIO_TCP ; }
bool hasUDP ( ) const { return ! ! pNetIO_UDP ; }
// initialization
2016-01-24 05:11:14 +00:00
bool Init ( int16_t iPortTCP , int16_t iPortUDP , int16_t iPortDiscovery = - 1 , int16_t iPortRefServer = - 1 , bool fBroadcast = false , bool enable_upnp = true ) ; // by main thread
2013-11-29 13:18:48 +00:00
void Clear ( ) ; // by main thread
void SetLocalCCore ( const C4ClientCore & CCore ) ; // by main thread
// i/o types
C4NetIO * MsgIO ( ) ; // by both
C4NetIO * DataIO ( ) ; // by both
// connections
2016-11-02 23:58:02 +00:00
bool Connect ( const C4NetIO : : addr_t & addr , C4Network2IOProtocol eProt , const C4ClientCore & nCCore , const char * szPassword = nullptr ) ; // by main thread
2013-11-29 13:18:48 +00:00
void SetAcceptMode ( bool fAcceptAll ) ; // by main thread
void SetExclusiveConnMode ( bool fExclusiveConn ) ; // by main thread
int getConnectionCount ( ) ; // by main thread
void ClearAutoAccept ( ) ; // by main thread
void AddAutoAccept ( const C4ClientCore & CCore ) ; // by main thread
void RemoveAutoAccept ( const C4ClientCore & CCore ) ; // by main thread
C4Network2IOConnection * GetMsgConnection ( int iClientID ) ; // by both (returns referenced connection!)
C4Network2IOConnection * GetDataConnection ( int iClientID ) ; // by both (returns referenced connection!)
// broadcasting
void BeginBroadcast ( bool fSelectAll = false ) ; // by both
void EndBroadcast ( ) ; // by both
bool Broadcast ( const C4NetIOPacket & rPkt ) ; // by both
// sending helpers
bool SendMsgToClient ( C4NetIOPacket & rPkt , int iClient ) ; // by both
bool BroadcastMsg ( const C4NetIOPacket & rPkt ) ; // by both
2016-09-07 21:46:22 +00:00
// punch
2016-10-20 19:14:08 +00:00
bool InitPuncher ( C4NetIO : : addr_t PuncherAddr ) ; // by main thread
2017-01-08 17:34:26 +00:00
void SendPuncherPacket ( const C4NetpuncherPacket & , C4NetIO : : HostAddress : : AddressFamily family ) ;
2016-10-20 19:14:08 +00:00
void Punch ( const C4NetIO : : addr_t & ) ; // sends a ping packet
2016-09-07 21:46:22 +00:00
2013-11-29 13:18:48 +00:00
// stuff
C4NetIO * getNetIO ( C4Network2IOProtocol eProt ) ; // by both
const char * getNetIOName ( C4NetIO * pNetIO ) ;
C4Network2IOProtocol getNetIOProt ( C4NetIO * pNetIO ) ;
// statistics
int getProtIRate ( C4Network2IOProtocol eProt ) const { return eProt = = P_TCP ? iTCPIRate : iUDPIRate ; }
int getProtORate ( C4Network2IOProtocol eProt ) const { return eProt = = P_TCP ? iTCPORate : iUDPORate ; }
int getProtBCRate ( C4Network2IOProtocol eProt ) const { return eProt = = P_TCP ? iTCPBCRate : iUDPBCRate ; }
// reference
void SetReference ( class C4Network2Reference * pReference ) ;
bool IsReferenceNeeded ( ) ;
protected :
// *** callbacks
// C4NetIO-Callbacks
virtual bool OnConn ( const C4NetIO : : addr_t & addr , const C4NetIO : : addr_t & AddrConnect , const C4NetIO : : addr_t * pOwnAddr , C4NetIO * pNetIO ) ;
virtual void OnDisconn ( const C4NetIO : : addr_t & addr , C4NetIO * pNetIO , const char * szReason ) ;
virtual void OnPacket ( const C4NetIOPacket & rPacket , C4NetIO * pNetIO ) ;
// C4NetIOMan
virtual void OnError ( const char * strError , C4NetIO * pNetIO ) ;
// StdSchedulerProc
virtual bool Execute ( int iTimeout , pollfd * ) ;
2013-12-04 12:35:07 +00:00
virtual C4TimeMilliseconds GetNextTick ( C4TimeMilliseconds tNow ) ;
2013-11-29 13:18:48 +00:00
// Event callback by C4InteractiveThread
void OnThreadEvent ( C4InteractiveEventType eEvent , void * pEventData ) ; // by main thread
// connections list
void AddConnection ( C4Network2IOConnection * pConn ) ; // by both
void RemoveConnection ( C4Network2IOConnection * pConn ) ; // by both
C4Network2IOConnection * GetConnection ( const C4NetIO : : addr_t & addr , C4NetIO * pNetIO ) ; // by both
C4Network2IOConnection * GetConnectionByConnAddr ( const C4NetIO : : addr_t & addr , C4NetIO * pNetIO ) ; // by both
C4Network2IOConnection * GetConnectionByID ( uint32_t iConnID ) ; // by thread
// network events (signals to main thread)
struct NetEvPacketData ;
// connection acceptance
bool doAutoAccept ( const C4ClientCore & CCore , const C4Network2IOConnection & Conn ) ;
// general packet handling (= forward in most cases)
bool HandlePacket ( const C4NetIOPacket & rPacket , C4Network2IOConnection * pConn , bool fThread ) ; // by both
void CallHandlers ( int iHandlers , const class C4IDPacket * pPacket , C4Network2IOConnection * pConn , bool fThread ) ; // by both
// packet handling (some are really handled here)
void HandlePacket ( char cStatus , const C4PacketBase * pPacket , C4Network2IOConnection * pConn ) ;
void HandleFwdReq ( const class C4PacketFwd & rFwd , C4Network2IOConnection * pBy ) ;
2016-10-20 19:14:08 +00:00
void HandlePuncherPacket ( const C4NetIOPacket & rPacket ) ;
2013-11-29 13:18:48 +00:00
// misc
bool Ping ( ) ;
void CheckTimeout ( ) ;
void GenerateStatistics ( int iInterval ) ;
void SendConnPackets ( ) ;
2016-09-07 21:46:22 +00:00
// puncher
2016-10-20 19:14:08 +00:00
void OnPuncherConnect ( C4NetIO : : addr_t addr ) ;
2013-11-29 13:18:48 +00:00
} ;
enum C4Network2IOConnStatus
{
CS_Connect , // waiting for connection
CS_Connected , // waiting for Conn
CS_HalfAccepted , // got Conn (peer identified, client class created if neccessary)
CS_Accepted , // got ConnRe (peer did accept)
CS_Closed ,
CS_ConnectFail // got closed before HalfAccepted was reached
} ;
class C4Network2IOConnection // shared
{
friend class C4Network2IO ;
public :
C4Network2IOConnection ( ) ;
~ C4Network2IOConnection ( ) ;
protected :
// connection data
class C4NetIO * pNetClass ;
C4Network2IOProtocol eProt ;
C4NetIO : : addr_t PeerAddr , ConnectAddr ;
// status data
C4Network2IOConnStatus Status ;
uint32_t iID , iRemoteID ; // connection ID for this and the remote client
bool fAutoAccept ; // auto accepted by thread?
bool fBroadcastTarget ; // broadcast target?
time_t iTimestamp ; // timestamp of last status change
int iPingTime ; // ping
2016-11-02 23:58:02 +00:00
C4TimeMilliseconds tLastPing ; // if > iLastPong, it's the first ping that hasn't been answered yet, nullptr if no ping received yet
C4TimeMilliseconds tLastPong ; // last pong received, nullptr if no pong received yet
2013-11-29 13:18:48 +00:00
C4ClientCore CCore ; // client core (>= CS_HalfAccepted)
CStdCSec CCoreCSec ;
int iIRate , iORate ; // input/output rates (by C4NetIO, in b/s)
int iPacketLoss ; // lost packets (in the last seconds)
StdCopyStrBuf Password ; // password to use for connect
bool fConnSent ; // initial connection packet send
bool fPostMortemSent ; // post mortem send
// packet backlog
uint32_t iOutPacketCounter , iInPacketCounter ;
struct PacketLogEntry
{
uint32_t Number ;
C4NetIOPacket Pkt ;
PacketLogEntry * Next ;
} ;
PacketLogEntry * pPacketLog ;
CStdCSec PacketLogCSec ;
// list (C4Network2IO)
C4Network2IOConnection * pNext ;
// reference counter
long iRefCnt ;
public :
C4NetIO * getNetClass ( ) const { return pNetClass ; }
C4Network2IOProtocol getProtocol ( ) const { return eProt ; }
2013-02-18 14:30:00 +00:00
const C4NetIO : : addr_t & getPeerAddr ( ) const { return PeerAddr . GetPort ( ) ? PeerAddr : ConnectAddr ; }
2013-11-29 13:18:48 +00:00
const C4NetIO : : addr_t & getConnectAddr ( ) const { return ConnectAddr ; }
uint32_t getID ( ) const { return iID ; }
uint32_t getRemoteID ( ) const { return iRemoteID ; }
time_t getTimestamp ( ) const { return iTimestamp ; }
const C4ClientCore & getCCore ( ) const { return CCore ; }
CStdCSec & getCCoreCSec ( ) { return CCoreCSec ; }
int getClientID ( ) const { return CCore . getID ( ) ; }
bool isHost ( ) const { return CCore . isHost ( ) ; }
int getPingTime ( ) const { return iPingTime ; }
int getLag ( ) const ;
int getIRate ( ) const { return iIRate ; }
int getORate ( ) const { return iORate ; }
int getPacketLoss ( ) const { return iPacketLoss ; }
const char * getPassword ( ) const { return Password . getData ( ) ; }
bool isConnSent ( ) const { return fConnSent ; }
uint32_t getInPacketCounter ( ) const { return iInPacketCounter ; }
uint32_t getOutPacketCounter ( ) const { return iOutPacketCounter ; }
bool isConnecting ( ) const { return Status = = CS_Connect ; }
bool isOpen ( ) const { return Status ! = CS_Connect & & Status ! = CS_Closed & & Status ! = CS_ConnectFail ; }
bool isHalfAccepted ( ) const { return Status = = CS_HalfAccepted | | Status = = CS_Accepted ; }
bool isAccepted ( ) const { return Status = = CS_Accepted ; }
bool isClosed ( ) const { return Status = = CS_Closed | | Status = = CS_ConnectFail ; }
bool isAutoAccepted ( ) const { return fAutoAccept ; }
bool isBroadcastTarget ( ) const { return fBroadcastTarget ; }
bool isFailed ( ) const { return Status = = CS_ConnectFail ; }
protected :
// called by C4Network2IO only
void Set ( C4NetIO * pnNetClass , C4Network2IOProtocol eProt , const C4NetIO : : addr_t & nPeerAddr , const C4NetIO : : addr_t & nConnectAddr , C4Network2IOConnStatus nStatus , const char * szPassword , uint32_t iID ) ;
void SetRemoteID ( uint32_t iRemoteID ) ;
void SetPeerAddr ( const C4NetIO : : addr_t & nPeerAddr ) ;
void OnPing ( ) ;
void SetPingTime ( int iPingTime ) ;
void SetStatus ( C4Network2IOConnStatus nStatus ) ;
void SetAutoAccepted ( ) ;
void OnPacketReceived ( uint8_t iPacketType ) ;
void ClearPacketLog ( uint32_t iStartNumber = ~ 0 ) ;
public :
// status changing
void SetHalfAccepted ( ) { SetStatus ( CS_HalfAccepted ) ; }
void SetAccepted ( ) { SetStatus ( CS_Accepted ) ; }
void SetCCore ( const C4ClientCore & nCCore ) ;
void ResetAutoAccepted ( ) { fAutoAccept = false ; }
void SetConnSent ( ) { fConnSent = true ; }
// connection operations
bool Connect ( ) ;
void Close ( ) ;
bool Send ( const C4NetIOPacket & rPkt ) ;
void SetBroadcastTarget ( bool fSet ) ; // (only call after C4Network2IO::BeginBroadcast!)
// statistics
void DoStatistics ( int iInterval , int * pIRateSum , int * pORateSum ) ;
// reference counting
void AddRef ( ) ; void DelRef ( ) ;
// post mortem
bool CreatePostMortem ( class C4PacketPostMortem * pPkt ) ;
} ;
// * Packets *
class C4PacketPing : public C4PacketBase
{
public :
C4PacketPing ( uint32_t iPacketCounter = 0 , uint32_t iRemotePacketCounter = 0 ) ;
protected :
2013-12-04 12:35:07 +00:00
C4TimeMilliseconds tTime ;
2013-11-29 13:18:48 +00:00
uint32_t iPacketCounter ;
public :
uint32_t getTravelTime ( ) const ;
uint32_t getPacketCounter ( ) const { return iPacketCounter ; }
virtual void CompileFunc ( StdCompiler * pComp ) ;
} ;
class C4PacketConn : public C4PacketBase
{
public :
C4PacketConn ( ) ;
2016-11-02 23:58:02 +00:00
C4PacketConn ( const class C4ClientCore & nCCore , uint32_t iConnID , const char * szPassword = nullptr ) ;
2013-11-29 13:18:48 +00:00
protected :
int32_t iVer ;
uint32_t iConnID ;
C4ClientCore CCore ;
StdCopyStrBuf Password ;
public :
int32_t getVer ( ) const { return iVer ; }
uint32_t getConnID ( ) const { return iConnID ; }
const C4ClientCore & getCCore ( ) const { return CCore ; }
const char * getPassword ( ) const { return Password . getData ( ) ; }
virtual void CompileFunc ( StdCompiler * pComp ) ;
} ;
class C4PacketConnRe : public C4PacketBase
{
public :
C4PacketConnRe ( ) ;
2016-11-02 23:58:02 +00:00
C4PacketConnRe ( bool fOK , bool fWrongPassword , const char * szMsg = nullptr ) ;
2013-11-29 13:18:48 +00:00
protected :
bool fOK , fWrongPassword ;
StdStrBuf szMsg ;
public :
bool isOK ( ) const { return fOK ; }
bool isPasswordWrong ( ) const { return fWrongPassword ; }
const char * getMsg ( ) const { return szMsg . getData ( ) ; }
virtual void CompileFunc ( StdCompiler * pComp ) ;
} ;
class C4PacketFwd : public C4PacketBase
{
public :
C4PacketFwd ( ) ;
C4PacketFwd ( const StdBuf & Pkt ) ;
protected :
bool fNegativeList ;
int32_t iClients [ C4NetMaxClients ] ;
int32_t iClientCnt ;
StdCopyBuf Data ;
public :
const StdCopyBuf & getData ( ) const { return Data ; }
bool isNegativeList ( ) const { return fNegativeList ; }
int32_t getClient ( int32_t i ) const { return iClients [ i ] ; }
int32_t getClientCnt ( ) const { return iClientCnt ; }
bool DoFwdTo ( int32_t iClient ) const ;
void SetData ( const StdBuf & Pkt ) ;
void SetListType ( bool fnNegativeList ) ;
void AddClient ( int32_t iClient ) ;
virtual void CompileFunc ( StdCompiler * pComp ) ;
} ;
class C4PacketPostMortem : public C4PacketBase
{
public :
C4PacketPostMortem ( ) ;
~ C4PacketPostMortem ( ) ;
private :
uint32_t iConnID ;
uint32_t iPacketCounter ; // last packet counter of dead connection
uint32_t iPacketCount ;
struct PacketLink
{
C4NetIOPacket Pkt ;
PacketLink * Next ;
} ;
PacketLink * pPackets ;
public :
uint32_t getConnID ( ) const { return iConnID ; }
uint32_t getPacketCount ( ) const { return iPacketCount ; }
void SetConnID ( uint32_t inConnID ) { iConnID = inConnID ; }
const C4NetIOPacket * getPacket ( uint32_t iNumber ) const ;
void SetPacketCounter ( uint32_t iPacketCounter ) ;
void Add ( const C4NetIOPacket & rPkt ) ;
virtual void CompileFunc ( StdCompiler * pComp ) ;
} ;
# endif