| 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 | |
| 31 | class C4Network2; class C4Network2IOConnection; |
| 32 | |
| 33 | // retry count and interval for connecting a client |
| 34 | const int32_t C4NetClientConnectAttempts = 3, |
| 35 | C4NetClientConnectInterval = 6; // s |
| 36 | |
| 37 | // network client status (host only) |
| 38 | enum 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 | |
| 47 | class C4Network2Client |
| 48 | { |
| 49 | friend class C4Network2ClientList; |
| 50 | |
| 51 | public: |
| 52 | C4Network2Client(std::shared_ptr<spdlog::logger> logger, C4Client *pClient); |
| 53 | ~C4Network2Client(); |
| 54 | |
| 55 | protected: |
| 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 | |
| 94 | public: |
| 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 | |
| 153 | class C4Network2ClientList |
| 154 | { |
| 155 | public: |
| 156 | C4Network2ClientList(C4Network2IO *pIO); |
| 157 | ~C4Network2ClientList(); |
| 158 | |
| 159 | protected: |
| 160 | C4Network2IO *pIO; |
| 161 | C4Network2Client *pFirst; |
| 162 | C4Network2Client *pLocal; |
| 163 | C4ClientList *pClientList; |
| 164 | bool fHost; |
| 165 | std::shared_ptr<spdlog::logger> logger; |
| 166 | |
| 167 | public: |
| 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 | |
| 206 | class C4PacketAddr : public C4PacketBase |
| 207 | { |
| 208 | public: |
| 209 | C4PacketAddr() {} |
| 210 | C4PacketAddr(int32_t iClientID, const C4Network2Address &addr) |
| 211 | : iClientID(iClientID), addr(addr) {} |
| 212 | |
| 213 | protected: |
| 214 | int32_t iClientID; |
| 215 | C4Network2Address addr; |
| 216 | |
| 217 | public: |
| 218 | int32_t getClientID() const { return iClientID; } |
| 219 | const C4Network2Address &getAddr() const { return addr; } |
| 220 | |
| 221 | virtual void CompileFunc(StdCompiler *pComp) override; |
| 222 | }; |
| 223 | |
| 224 | class C4PacketTCPSimOpen : public C4PacketBase |
| 225 | { |
| 226 | public: |
| 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 | |
| 236 | private: |
| 237 | std::int32_t clientID; |
| 238 | C4Network2Address addr; |
| 239 | }; |
| 240 | |