1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/*
* This file is part of OpenTTD.
* OpenTTD 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, version 2.
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file network_coordinator.h Part of the network protocol handling Game Coordinator requests. */
#ifndef NETWORK_COORDINATOR_H
#define NETWORK_COORDINATOR_H
#include "core/tcp_coordinator.h"
#include "network_stun.h"
#include "network_turn.h"
#include <map>
/**
* Game Coordinator communication.
* For more detail about what the Game Coordinator does, please see
* docs/game_coordinator.md.
*
* For servers:
* - Server sends SERVER_REGISTER.
* - Game Coordinator probes server to check if it can directly connect.
* - Game Coordinator sends GC_REGISTER_ACK with type of connection.
* - Server sends every 30 seconds SERVER_UPDATE.
*
* For clients (listing):
* - Client sends CLIENT_LISTING.
* - Game Coordinator returns the full list of public servers via GC_LISTING (multiple packets).
*
* For clients (connecting):
* - Client sends CLIENT_CONNECT.
* - Game Coordinator checks what type of connections the servers supports:
* 1) Direct connect?
* - Send the client a GC_CONNECT with the peer address.
* - a) Client connects, client sends CLIENT_CONNECTED to Game Coordinator.
* - b) Client connect fails, client sends CLIENT_CONNECT_FAILED to Game Coordinator.
* 2) STUN?
* - Game Coordinator sends GC_STUN_REQUEST to server/client (asking for both IPv4 and IPv6 STUN requests).
* - Game Coordinator collects what combination works and sends GC_STUN_CONNECT to server/client.
* - a) Server/client connect, client sends CLIENT_CONNECTED to Game Coordinator.
* - b) Server/client connect fails, both send SERCLI_CONNECT_FAILED to Game Coordinator.
* - Game Coordinator tries other combination if available.
* 3) TURN?
* - Game Coordinator sends GC_TURN_CONNECT to server/client.
* - a) Server/client connect, client sends CLIENT_CONNECTED to Game Coordinator.
* - b) Server/client connect fails, both send SERCLI_CONNECT_FAILED to Game Coordinator.
* - If all fails, Game Coordinator sends GC_CONNECT_FAILED to indicate no connection is possible.
*/
/** Class for handling the client side of the Game Coordinator connection. */
class ClientNetworkCoordinatorSocketHandler : public NetworkCoordinatorSocketHandler {
private:
std::chrono::steady_clock::time_point next_update; ///< When to send the next update (if server and public).
std::map<std::string, std::pair<std::string, TCPServerConnecter *>> connecter; ///< Based on tokens, the current (invite-code, connecter) that are pending.
std::map<std::string, TCPServerConnecter *> connecter_pre; ///< Based on invite codes, the current connecters that are pending.
std::map<std::string, std::map<int, std::unique_ptr<ClientNetworkStunSocketHandler>>> stun_handlers; ///< All pending STUN handlers, stored by token:family.
std::map<std::string, std::unique_ptr<ClientNetworkTurnSocketHandler>> turn_handlers; ///< Pending TURN handler (if any), stored by token.
TCPConnecter *game_connecter = nullptr; ///< Pending connecter to the game server.
uint32 newgrf_lookup_table_cursor = 0; ///< Last received cursor for the #GameInfoNewGRFLookupTable updates.
GameInfoNewGRFLookupTable newgrf_lookup_table; ///< Table to look up NewGRFs in the GC_LISTING packets.
protected:
bool Receive_GC_ERROR(Packet *p) override;
bool Receive_GC_REGISTER_ACK(Packet *p) override;
bool Receive_GC_LISTING(Packet *p) override;
bool Receive_GC_CONNECTING(Packet *p) override;
bool Receive_GC_CONNECT_FAILED(Packet *p) override;
bool Receive_GC_DIRECT_CONNECT(Packet *p) override;
bool Receive_GC_STUN_REQUEST(Packet *p) override;
bool Receive_GC_STUN_CONNECT(Packet *p) override;
bool Receive_GC_NEWGRF_LOOKUP(Packet *p) override;
bool Receive_GC_TURN_CONNECT(Packet *p) override;
public:
/** The idle timeout; when to close the connection because it's idle. */
static constexpr std::chrono::seconds IDLE_TIMEOUT = std::chrono::seconds(60);
std::chrono::steady_clock::time_point last_activity; ///< The last time there was network activity.
bool connecting; ///< Are we connecting to the Game Coordinator?
ClientNetworkCoordinatorSocketHandler() : connecting(false) {}
NetworkRecvStatus CloseConnection(bool error = true) override;
void SendReceive();
void ConnectFailure(const std::string &token, uint8 tracking_number);
void ConnectSuccess(const std::string &token, SOCKET sock, NetworkAddress &address);
void StunResult(const std::string &token, uint8 family, bool result);
void Connect();
void CloseToken(const std::string &token);
void CloseAllConnections();
void CloseStunHandler(const std::string &token, uint8 family = AF_UNSPEC);
void CloseTurnHandler(const std::string &token);
void Register();
void SendServerUpdate();
void GetListing();
void ConnectToServer(const std::string &invite_code, TCPServerConnecter *connecter);
void StartTurnConnection(std::string &token);
};
extern ClientNetworkCoordinatorSocketHandler _network_coordinator_client;
#endif /* NETWORK_COORDINATOR_H */
|