1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2011-2018, The OpenClonk Team and contributors
6 * Copyright (c) 2017-2021, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18#pragma once
19
20#include "C4NetIO.h"
21#include "C4Network2IO.h"
22#include "C4PacketBase.h"
23#include "C4Client.h"
24#include "C4Network2Address.h"
25
26#include <cstddef>
27#include <cstdint>
28#include <set>
29#include <vector>
30
31class C4Network2; class C4Network2IOConnection;
32
33// retry count and interval for connecting a client
34const int32_t C4NetClientConnectAttempts = 3,
35 C4NetClientConnectInterval = 6; // s
36
37// network client status (host only)
38enum C4Network2ClientStatus
39{
40 NCS_Joining, // waiting for join data
41 NCS_Chasing, // client is behind (status not acknowledged, isn't waited for)
42 NCS_NotReady, // client is behind (status not acknowledged)
43 NCS_Ready, // client acknowledged network status
44 NCS_Remove, // client is to be removed
45};
46
47class C4Network2Client
48{
49 friend class C4Network2ClientList;
50
51public:
52 C4Network2Client(std::shared_ptr<spdlog::logger> logger, C4Client *pClient);
53 ~C4Network2Client();
54
55protected:
56 struct ClientAddress
57 {
58 C4Network2Address Addr;
59 int32_t ConnectionAttempts{0};
60
61 ClientAddress(const C4Network2Address &addr) noexcept : Addr{addr} {}
62 };
63
64 std::shared_ptr<spdlog::logger> logger;
65
66 // client data
67 C4Client *pClient;
68
69 std::vector<ClientAddress> Addresses;
70 // addresses
71 C4NetIO::addr_t IPv6AddrFromPuncher;
72
73 // Interface ids
74 std::set<int> InterfaceIDs;
75
76 // status
77 C4Network2ClientStatus eStatus;
78
79 // frame of last activity
80 int32_t iLastActivity;
81
82 // connections
83 C4Network2IOConnection *pMsgConn, *pDataConn;
84 time_t iNextConnAttempt;
85 std::unique_ptr<C4NetIOTCP::Socket> tcpSimOpenSocket;
86
87 // part of client list
88 C4Network2Client *pNext;
89 class C4Network2ClientList *pParent;
90
91 // statistics
92 class C4TableGraph *pstatPing;
93
94public:
95 C4Client *getClient() const { return pClient; }
96 const C4ClientCore &getCore() const { return getClient()->getCore(); }
97 int32_t getID() const { return getCore().getID(); }
98 bool isLocal() const { return pClient->isLocal(); }
99 bool isHost() const { return getID() == C4ClientIDHost; }
100 const char *getName() const { return getCore().getName(); }
101 bool isActivated() const { return getCore().isActivated(); }
102 bool isObserver() const { return getCore().isObserver(); }
103
104 const std::vector<ClientAddress> &getAddresses() const { return Addresses; }
105 std::size_t getAddrCnt() const { return Addresses.size(); }
106 const C4Network2Address &getAddr(std::size_t i) const { return Addresses[i].Addr; }
107
108 const std::set<int> &getInterfaceIDs() const { return InterfaceIDs; }
109
110 C4Network2ClientStatus getStatus() const { return eStatus; }
111 bool hasJoinData() const { return getStatus() != NCS_Joining; }
112 bool isChasing() const { return getStatus() == NCS_Chasing; }
113 bool isReady() const { return getStatus() == NCS_Ready; }
114 bool isWaitedFor() const { return getStatus() == NCS_NotReady || getStatus() == NCS_Ready; }
115 bool isRemoved() const { return getStatus() == NCS_Remove; }
116
117 bool isConnected() const { return !!pMsgConn; }
118 time_t getNextConnAttempt() const { return iNextConnAttempt; }
119 int32_t getLastActivity() const { return iLastActivity; }
120 class C4TableGraph *getStatPing() const { return pstatPing; }
121
122 C4Network2Client *getNext() const { return pNext; }
123
124 void SetStatus(C4Network2ClientStatus enStatus) { eStatus = enStatus; }
125 void SetLastActivity(int32_t iTick) { iLastActivity = iTick; }
126
127 C4Network2IOConnection *getMsgConn() const { return pMsgConn; }
128 C4Network2IOConnection *getDataConn() const { return pDataConn; }
129 bool hasConn(C4Network2IOConnection *pConn);
130 void SetMsgConn(C4Network2IOConnection *pConn);
131 void SetDataConn(C4Network2IOConnection *pConn);
132 void RemoveConn(C4Network2IOConnection *pConn);
133 void CloseConns(const char *szMsg);
134
135 bool SendMsg(C4NetIOPacket rPkt) const;
136
137 bool DoConnectAttempt(class C4Network2IO *pIO);
138 bool DoTCPSimultaneousOpen(class C4Network2IO *pIO, const C4Network2Address &addr);
139
140 // addresses
141 bool hasAddr(const C4Network2Address &addr) const;
142 void AddAddrFromPuncher(const C4NetIO::addr_t &addr);
143 bool AddAddr(const C4Network2Address &addr, bool fAnnounce, bool inFront = false);
144 void AddLocalAddrs(std::uint16_t iPortTCP, std::uint16_t iPortUDP);
145
146 void SendAddresses(C4Network2IOConnection *pConn);
147
148 // runtime statistics
149 void CreateGraphs();
150 void ClearGraphs();
151};
152
153class C4Network2ClientList
154{
155public:
156 C4Network2ClientList(C4Network2IO *pIO);
157 ~C4Network2ClientList();
158
159protected:
160 C4Network2IO *pIO;
161 C4Network2Client *pFirst;
162 C4Network2Client *pLocal;
163 C4ClientList *pClientList;
164 bool fHost;
165 std::shared_ptr<spdlog::logger> logger;
166
167public:
168 C4Network2Client *GetClientByID(int32_t iID) const;
169 C4Network2Client *GetClient(const char *szName) const;
170 C4Network2Client *GetClient(const C4ClientCore &CCore, int32_t iMaxDiffLevel = C4ClientCoreDL_IDMatch);
171 C4Network2Client *GetClient(C4Network2IOConnection *pConn) const;
172 C4Network2Client *GetLocal() const { return pLocal; }
173 C4Network2Client *GetHost();
174 C4Network2Client *GetNextClient(C4Network2Client *pClient);
175
176 void Init(std::shared_ptr<spdlog::logger> logger, C4ClientList *pClientList, bool fHost);
177 C4Network2Client *RegClient(C4Client *pClient);
178 void DeleteClient(C4Network2Client *pClient);
179 void Clear();
180
181 // messages
182 bool BroadcastMsgToConnClients(const C4NetIOPacket &rPkt);
183 bool BroadcastMsgToClients(const C4NetIOPacket &rPkt, bool includeHost = false);
184 bool SendMsgToHost(C4NetIOPacket rPkt);
185 bool SendMsgToClient(int32_t iClient, C4NetIOPacket &&rPkt);
186
187 // packet handling
188 void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
189
190 // addresses
191 void SendAddresses(C4Network2IOConnection *pConn);
192
193 // connecting
194 void DoConnectAttempts();
195
196 // ready-ness
197 void ResetReady();
198 bool AllClientsReady() const;
199
200 // activity
201 void UpdateClientActivity();
202};
203
204// Packets
205
206class C4PacketAddr : public C4PacketBase
207{
208public:
209 C4PacketAddr() {}
210 C4PacketAddr(int32_t iClientID, const C4Network2Address &addr)
211 : iClientID(iClientID), addr(addr) {}
212
213protected:
214 int32_t iClientID;
215 C4Network2Address addr;
216
217public:
218 int32_t getClientID() const { return iClientID; }
219 const C4Network2Address &getAddr() const { return addr; }
220
221 virtual void CompileFunc(StdCompiler *pComp) override;
222};
223
224class C4PacketTCPSimOpen : public C4PacketBase
225{
226public:
227 C4PacketTCPSimOpen() = default;
228 C4PacketTCPSimOpen(const std::int32_t clientID, const C4Network2Address &addr)
229 : clientID{clientID}, addr{addr} {}
230
231 std::int32_t GetClientID() const { return clientID; }
232 const C4Network2Address &GetAddr() const { return addr; }
233
234 void CompileFunc(StdCompiler *comp) override;
235
236private:
237 std::int32_t clientID;
238 C4Network2Address addr;
239};
240