1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
3 #ifndef ENGINE_SHARED_NETWORK_H
4 #define ENGINE_SHARED_NETWORK_H
6 #include "ringbuffer.h"
12 packet header: 3 bytes
13 unsigned char flags_ack; // 4bit flags, 4bit ack
14 unsigned char ack; // 8 bit ack
15 unsigned char num_chunks; // 8 bit chunks
17 (unsigned char padding[3]) // 24 bit extra incase it's a connection less packet
18 // this is to make sure that it's compatible with the
21 chunk header: 2-3 bytes
22 unsigned char flags_size; // 2bit flags, 6 bit size
23 unsigned char size_seq; // 4bit size, 4bit seq
24 (unsigned char seq;) // 8bit seq, if vital flag is set
29 NETFLAG_ALLOWSTATELESS
=1,
31 NETSENDFLAG_CONNLESS
=2,
47 NET_MAX_PACKETSIZE
= 1400,
48 NET_MAX_PAYLOAD
= NET_MAX_PACKETSIZE
-6,
49 NET_MAX_CHUNKHEADERSIZE
= 5,
50 NET_PACKETHEADERSIZE
= 3,
52 NET_MAX_CONSOLE_CLIENTS
= 4,
53 NET_MAX_SEQUENCE
= 1<<10,
54 NET_SEQUENCE_MASK
= NET_MAX_SEQUENCE
-1,
56 NET_CONNSTATE_OFFLINE
=0,
57 NET_CONNSTATE_CONNECT
=1,
58 NET_CONNSTATE_PENDING
=2,
59 NET_CONNSTATE_ONLINE
=3,
60 NET_CONNSTATE_ERROR
=4,
62 NET_PACKETFLAG_CONTROL
=1,
63 NET_PACKETFLAG_CONNLESS
=2,
64 NET_PACKETFLAG_RESEND
=4,
65 NET_PACKETFLAG_COMPRESSION
=8,
67 NET_CHUNKFLAG_VITAL
=1,
68 NET_CHUNKFLAG_RESEND
=2,
70 NET_CTRLMSG_KEEPALIVE
=0,
71 NET_CTRLMSG_CONNECT
=1,
72 NET_CTRLMSG_CONNECTACCEPT
=2,
76 NET_SERVER_MAXBANS
=1024,
78 NET_CONN_BUFFERSIZE
=1024*32,
84 typedef int (*NETFUNC_DELCLIENT
)(int ClientID
, const char* pReason
, void *pUser
);
85 typedef int (*NETFUNC_NEWCLIENT
)(int ClientID
, void *pUser
);
89 // -1 means that it's a stateless packet
90 // 0 on the client means the server
92 NETADDR m_Address
; // only used when client_id == -1
105 unsigned char *Pack(unsigned char *pData
);
106 unsigned char *Unpack(unsigned char *pData
);
109 class CNetChunkResend
114 unsigned char *m_pData
;
117 int64 m_LastSendTime
;
118 int64 m_FirstSendTime
;
121 class CNetPacketConstruct
128 unsigned char m_aChunkData
[NET_MAX_PAYLOAD
];
134 // TODO: is this needed because this needs to be aware of
135 // the ack sequencing number and is also responible for updating
136 // that. this should be fixed.
137 friend class CNetRecvUnpacker
;
139 unsigned short m_Sequence
;
140 unsigned short m_Ack
;
146 TStaticRingBuffer
<CNetChunkResend
, NET_CONN_BUFFERSIZE
> m_Buffer
;
148 int64 m_LastUpdateTime
;
149 int64 m_LastRecvTime
;
150 int64 m_LastSendTime
;
152 char m_ErrorString
[256];
154 CNetPacketConstruct m_Construct
;
163 void SetError(const char *pString
);
164 void AckChunks(int Ack
);
166 int QueueChunkEx(int Flags
, int DataSize
, const void *pData
, int Sequence
);
167 void SendControl(int ControlMsg
, const void *pExtra
, int ExtraSize
);
168 void ResendChunk(CNetChunkResend
*pResend
);
172 void Init(NETSOCKET Socket
);
173 int Connect(NETADDR
*pAddr
);
174 void Disconnect(const char *pReason
);
179 int Feed(CNetPacketConstruct
*pPacket
, NETADDR
*pAddr
);
180 int QueueChunk(int Flags
, int DataSize
, const void *pData
);
182 const char *ErrorString();
184 int State() const { return m_State
; }
185 NETADDR
PeerAddress() const { return m_PeerAddr
; }
187 void ResetErrorString() { m_ErrorString
[0] = 0; }
188 const char *ErrorString() const { return m_ErrorString
; }
190 // Needed for GotProblems in NetClient
191 int64
LastRecvTime() const { return m_LastRecvTime
; }
193 int AckSequence() const { return m_Ack
; }
196 class CConsoleNetConnection
204 char m_aBuffer
[NET_MAX_PACKETSIZE
];
207 char m_aErrorString
[256];
209 bool m_LineEndingDetected
;
210 char m_aLineEnding
[3];
213 void Init(NETSOCKET Socket
, const NETADDR
*pAddr
);
214 void Disconnect(const char *pReason
);
216 int State() const { return m_State
; }
217 NETADDR
PeerAddress() const { return m_PeerAddr
; }
218 const char *ErrorString() const { return m_aErrorString
; }
222 int Send(const char *pLine
);
223 int Recv(char *pLine
, int MaxLength
);
226 class CNetRecvUnpacker
232 CNetConnection
*m_pConnection
;
235 CNetPacketConstruct m_Data
;
236 unsigned char m_aBuffer
[NET_MAX_PACKETSIZE
];
238 CNetRecvUnpacker() { Clear(); }
240 void Start(const NETADDR
*pAddr
, CNetConnection
*pConnection
, int ClientID
);
241 int FetchChunk(CNetChunk
*pChunk
);
259 CNetConnection m_Connection
;
278 CSlot m_aSlots
[NET_MAX_CLIENTS
];
280 int m_MaxClientsPerIP
;
283 CBan m_BanPool
[NET_SERVER_MAXBANS
];
284 CBan
*m_BanPool_FirstFree
;
285 CBan
*m_BanPool_FirstUsed
;
287 NETFUNC_NEWCLIENT m_pfnNewClient
;
288 NETFUNC_DELCLIENT m_pfnDelClient
;
291 CNetRecvUnpacker m_RecvUnpacker
;
293 void BanRemoveByObject(CBan
*pBan
);
296 int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient
, NETFUNC_DELCLIENT pfnDelClient
, void *pUser
);
299 bool Open(NETADDR BindAddr
, int MaxClients
, int MaxClientsPerIP
, int Flags
);
303 int Recv(CNetChunk
*pChunk
);
304 int Send(CNetChunk
*pChunk
);
308 int Drop(int ClientID
, const char *pReason
);
311 int BanAdd(NETADDR Addr
, int Seconds
, const char *pReason
);
312 int BanRemove(NETADDR Addr
);
313 int BanNum(); // caution, slow
314 int BanGet(int Index
, CBanInfo
*pInfo
); // caution, slow
317 NETADDR
ClientAddr(int ClientID
) const { return m_aSlots
[ClientID
].m_Connection
.PeerAddress(); }
318 NETSOCKET
Socket() const { return m_Socket
; }
319 int NetType() { return m_Socket
.type
; }
320 int MaxClients() const { return m_MaxClients
; }
323 void SetMaxClientsPerIP(int Max
);
333 int FindBan(NETADDR Addr
);
345 CConsoleNetConnection m_Connection
;
349 CSlot m_aSlots
[NET_MAX_CONSOLE_CLIENTS
];
351 NETFUNC_NEWCLIENT m_pfnNewClient
;
352 NETFUNC_DELCLIENT m_pfnDelClient
;
355 CNetRecvUnpacker m_RecvUnpacker
;
358 void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient
, NETFUNC_DELCLIENT pfnDelClient
, void *pUser
);
361 bool Open(NETADDR BindAddr
, int Flags
);
365 int Recv(char *pLine
, int MaxLength
, int *pClientID
= 0);
366 int Send(int ClientID
, const char *pLine
);
370 int AcceptClient(NETSOCKET Socket
, const NETADDR
*pAddr
);
371 int Drop(int ClientID
, const char *pReason
);
373 bool AddBan(NETADDR Addr
, int Seconds
);
376 NETADDR
ClientAddr(int ClientID
) const { return m_aSlots
[ClientID
].m_Connection
.PeerAddress(); }
384 NETADDR m_ServerAddr
;
385 CNetConnection m_Connection
;
386 CNetRecvUnpacker m_RecvUnpacker
;
390 bool Open(NETADDR BindAddr
, int Flags
);
394 int Disconnect(const char *Reason
);
395 int Connect(NETADDR
*Addr
);
398 int Recv(CNetChunk
*Chunk
);
399 int Send(CNetChunk
*Chunk
);
405 int ResetErrorString();
408 int NetType() { return m_Socket
.type
; }
411 const char *ErrorString();
416 // TODO: both, fix these. This feels like a junk class for stuff that doesn't fit anywere
419 static IOHANDLE ms_DataLogSent
;
420 static IOHANDLE ms_DataLogRecv
;
421 static CHuffman ms_Huffman
;
423 static void OpenLog(IOHANDLE DataLogSent
, IOHANDLE DataLogRecv
);
424 static void CloseLog();
426 static int Compress(const void *pData
, int DataSize
, void *pOutput
, int OutputSize
);
427 static int Decompress(const void *pData
, int DataSize
, void *pOutput
, int OutputSize
);
429 static void SendControlMsg(NETSOCKET Socket
, NETADDR
*pAddr
, int Ack
, int ControlMsg
, const void *pExtra
, int ExtraSize
);
430 static void SendPacketConnless(NETSOCKET Socket
, NETADDR
*pAddr
, const void *pData
, int DataSize
);
431 static void SendPacket(NETSOCKET Socket
, NETADDR
*pAddr
, CNetPacketConstruct
*pPacket
);
432 static int UnpackPacket(unsigned char *pBuffer
, int Size
, CNetPacketConstruct
*pPacket
);
434 // The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not
435 static int IsSeqInBackroom(int Seq
, int Ack
);