OpenTTD Source  20241108-master-g80f628063a
network_stun.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "../debug.h"
12 #include "network.h"
13 #include "network_coordinator.h"
14 #include "network_stun.h"
15 
16 #include "../safeguards.h"
17 
20 private:
21  ClientNetworkStunSocketHandler *stun_handler;
22  std::string token;
23  uint8_t family;
24 
25 public:
31  NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, const std::string &connection_string, const std::string &token, uint8_t family) :
33  stun_handler(stun_handler),
34  token(token),
35  family(family)
36  {
37  }
38 
39  void OnFailure() override
40  {
41  Debug(net, 9, "Stun::OnFailure(): family={}", this->family);
42 
43  this->stun_handler->connecter = nullptr;
44 
45  /* Connection to STUN server failed. For example, the client doesn't
46  * support IPv6, which means it will fail that attempt. */
47 
48  _network_coordinator_client.StunResult(this->token, this->family, false);
49  }
50 
51  void OnConnect(SOCKET s) override
52  {
53  Debug(net, 9, "Stun::OnConnect(): family={}", this->family);
54 
55  this->stun_handler->connecter = nullptr;
56 
57  assert(this->stun_handler->sock == INVALID_SOCKET);
58  this->stun_handler->sock = s;
59 
60  /* Store the local address; later connects will reuse it again.
61  * This is what makes STUN work for most NATs. */
62  this->stun_handler->local_addr = NetworkAddress::GetSockAddress(s);
63 
64  /* We leave the connection open till the real connection is setup later. */
65  }
66 };
67 
73 void ClientNetworkStunSocketHandler::Connect(const std::string &token, uint8_t family)
74 {
75  this->token = token;
76  this->family = family;
77 
78  Debug(net, 9, "Stun::Connect(): family={}", this->family);
79 
80  this->connecter = TCPConnecter::Create<NetworkStunConnecter>(this, NetworkStunConnectionString(), token, family);
81 }
82 
89 std::unique_ptr<ClientNetworkStunSocketHandler> ClientNetworkStunSocketHandler::Stun(const std::string &token, uint8_t family)
90 {
91  auto stun_handler = std::make_unique<ClientNetworkStunSocketHandler>();
92 
93  stun_handler->Connect(token, family);
94 
95  auto p = std::make_unique<Packet>(stun_handler.get(), PACKET_STUN_SERCLI_STUN);
96  p->Send_uint8(NETWORK_COORDINATOR_VERSION);
97  p->Send_string(token);
98  p->Send_uint8(family);
99 
100  stun_handler->SendPacket(std::move(p));
101 
102  return stun_handler;
103 }
104 
106 {
108 
109  /* Also make sure any pending connecter is killed ASAP. */
110  if (this->connecter != nullptr) {
111  this->connecter->Kill();
112  this->connecter = nullptr;
113  }
114 
116 }
117 
118 ClientNetworkStunSocketHandler::~ClientNetworkStunSocketHandler()
119 {
120  if (this->connecter != nullptr) {
121  this->connecter->Kill();
122  this->connecter = nullptr;
123  }
124 }
125 
131 {
132  if (this->sock == INVALID_SOCKET) return;
133 
134  /* We never attempt to receive anything on a STUN socket. After
135  * connecting a STUN connection, the local address will be reused to
136  * to establish the connection with the real server. If we would be to
137  * read this socket, some OSes get confused and deliver us packets meant
138  * for the real connection. It appears most OSes play best when we simply
139  * never attempt to read it to start with (and the packets will remain
140  * available on the other socket).
141  * Protocol-wise, the STUN server will never send any packet back anyway. */
142 
143  this->CanSendReceive();
144  if (this->SendPackets() == SPS_ALL_SENT && !this->sent_result) {
145  /* We delay giving the GC the result this long, as to make sure we
146  * have sent the STUN packet first. This means the GC is more likely
147  * to have the result ready by the time our StunResult() packet
148  * arrives. */
149  this->sent_result = true;
151  }
152 }
void StunResult(const std::string &token, uint8_t family, bool result)
Callback from the STUN connecter to inform the Game Coordinator about the result of the STUN.
Class for handling the client side of the STUN connection.
Definition: network_stun.h:16
void Connect(const std::string &token, uint8_t family)
Connect to the STUN server over either IPv4 or IPv6.
std::string token
Token of this STUN handler.
Definition: network_stun.h:18
void SendReceive()
Check whether we received/can send some data from/to the STUN server and when that's the case handle ...
uint8_t family
Family of this STUN handler.
Definition: network_stun.h:19
static std::unique_ptr< ClientNetworkStunSocketHandler > Stun(const std::string &token, uint8_t family)
Send a STUN packet to the STUN server.
std::shared_ptr< TCPConnecter > connecter
Connecter instance.
Definition: network_stun.h:23
NetworkAddress local_addr
Local addresses of the socket.
Definition: network_stun.h:24
NetworkRecvStatus CloseConnection(bool error=true) override
This will put this socket handler in a close state.
bool sent_result
Did we sent the result of the STUN connection?
Definition: network_stun.h:20
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
Definition: address.h:28
static NetworkAddress GetSockAddress(SOCKET sock)
Get the local address of a socket as NetworkAddress.
Definition: address.cpp:419
Connect to the STUN server.
NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, const std::string &connection_string, const std::string &token, uint8_t family)
Initiate the connecting.
void OnFailure() override
Callback for when the connection attempt failed.
virtual NetworkRecvStatus CloseConnection(bool error=true)
This will put this socket handler in a close state.
Definition: tcp.cpp:51
SOCKET sock
The socket currently connected to.
Definition: tcp.h:38
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition: tcp.cpp:86
bool CanSendReceive()
Check whether this socket can send or receive something.
Definition: tcp.cpp:204
"Helper" class for creating TCP connections in a non-blocking manner
Definition: tcp.h:70
std::string connection_string
Current address we are connecting to (before resolving).
Definition: tcp.h:99
const char * NetworkStunConnectionString()
Get the connection string for the STUN server from the environment variable OTTD_STUN_CS,...
Definition: config.cpp:45
static const uint16_t NETWORK_STUN_SERVER_PORT
The default port of the STUN server (TCP)
Definition: config.h:22
static const uint8_t NETWORK_COORDINATOR_VERSION
What version of game-coordinator-protocol do we use?
Definition: config.h:50
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition: core.h:23
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition: core.h:24
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
Basic functions/variables used all over the place.
ClientNetworkCoordinatorSocketHandler _network_coordinator_client
The connection to the Game Coordinator.
Part of the network protocol handling Game Coordinator requests.
Part of the network protocol handling STUN requests.
@ SPS_ALL_SENT
All packets in the queue are sent.
Definition: tcp.h:27
@ PACKET_STUN_SERCLI_STUN
Send a STUN request to the STUN server.
Definition: tcp_stun.h:21