OpenTTD Source 20260206-master-g4d4e37dbf1
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11
12#include "../debug.h"
13#include "network_coordinator.h"
14#include "network_stun.h"
15
16#include "../safeguards.h"
17
19class NetworkStunConnecter : public TCPConnecter {
20private:
22 std::string token;
23 uint8_t family;
24
25public:
33 NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, std::string_view connection_string, std::string_view token, uint8_t family) :
35 stun_handler(stun_handler),
36 token(token),
37 family(family)
38 {
39 }
40
41 void OnFailure() override
42 {
43 Debug(net, 9, "Stun::OnFailure(): family={}", this->family);
44
45 this->stun_handler->connecter = nullptr;
46
47 /* Connection to STUN server failed. For example, the client doesn't
48 * support IPv6, which means it will fail that attempt. */
49
50 _network_coordinator_client.StunResult(this->token, this->family, false);
51 }
52
53 void OnConnect(SOCKET s) override
54 {
55 Debug(net, 9, "Stun::OnConnect(): family={}", this->family);
56
57 this->stun_handler->connecter = nullptr;
58
59 assert(this->stun_handler->sock == INVALID_SOCKET);
60 this->stun_handler->sock = s;
61
62 /* Store the local address; later connects will reuse it again.
63 * This is what makes STUN work for most NATs. */
64 this->stun_handler->local_addr = NetworkAddress::GetSockAddress(s);
65
66 /* We leave the connection open till the real connection is setup later. */
67 }
68};
69
76{
77 this->token = token;
78 this->family = family;
79
80 Debug(net, 9, "Stun::Connect(): family={}", this->family);
81
83}
84
91std::unique_ptr<ClientNetworkStunSocketHandler> ClientNetworkStunSocketHandler::Stun(std::string_view token, uint8_t family)
92{
93 auto stun_handler = std::make_unique<ClientNetworkStunSocketHandler>();
94
95 stun_handler->Connect(token, family);
96
97 auto p = std::make_unique<Packet>(stun_handler.get(), PACKET_STUN_SERCLI_STUN);
98 p->Send_uint8(NETWORK_COORDINATOR_VERSION);
99 p->Send_string(token);
100 p->Send_uint8(family);
101
102 Debug(net, 9, "Stun::SendStun({}, {})", token, family);
103 stun_handler->SendPacket(std::move(p));
104
105 return stun_handler;
106}
107
109{
111
112 /* Also make sure any pending connecter is killed ASAP. */
113 if (this->connecter != nullptr) {
114 this->connecter->Kill();
115 this->connecter = nullptr;
116 }
117
119}
120
121ClientNetworkStunSocketHandler::~ClientNetworkStunSocketHandler()
122{
123 if (this->connecter != nullptr) {
124 this->connecter->Kill();
125 this->connecter = nullptr;
126 }
127}
128
134{
135 if (this->sock == INVALID_SOCKET) return;
136
137 /* We never attempt to receive anything on a STUN socket. After
138 * connecting a STUN connection, the local address will be reused to
139 * to establish the connection with the real server. If we would be to
140 * read this socket, some OSes get confused and deliver us packets meant
141 * for the real connection. It appears most OSes play best when we simply
142 * never attempt to read it to start with (and the packets will remain
143 * available on the other socket).
144 * Protocol-wise, the STUN server will never send any packet back anyway. */
145
146 this->CanSendReceive();
147 if (this->SendPackets() == SPS_ALL_SENT && !this->sent_result) {
148 /* We delay giving the GC the result this long, as to make sure we
149 * have sent the STUN packet first. This means the GC is more likely
150 * to have the result ready by the time our StunResult() packet
151 * arrives. */
152 this->sent_result = true;
153 _network_coordinator_client.StunResult(this->token, this->family, true);
154 }
155}
Class for handling the client side of the STUN connection.
std::string token
Token of this STUN handler.
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.
std::shared_ptr< TCPConnecter > connecter
Connecter instance.
NetworkAddress local_addr
Local addresses of the socket.
void Connect(std::string_view token, uint8_t family)
Connect to the STUN server over either IPv4 or IPv6.
static std::unique_ptr< ClientNetworkStunSocketHandler > Stun(std::string_view token, uint8_t family)
Send a STUN packet to the STUN server.
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?
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:413
NetworkStunConnecter(ClientNetworkStunSocketHandler *stun_handler, std::string_view connection_string, std::string_view token, uint8_t family)
Initiate the connecting.
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
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:39
SOCKET sock
The socket currently connected to.
Definition tcp.h:36
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition tcp.cpp:74
bool CanSendReceive()
Check whether this socket can send or receive something.
Definition tcp.cpp:192
std::string connection_string
Current address we are connecting to (before resolving).
Definition tcp.h:101
static std::shared_ptr< TCPConnecter > Create(Args &&... args)
Create the connecter, and initiate connecting by putting it in the collection of TCP connections to m...
Definition tcp.h:147
std::string_view NetworkStunConnectionString()
Get the connection string for the STUN server from the environment variable OTTD_STUN_CS,...
Definition config.cpp:31
static const uint16_t NETWORK_STUN_SERVER_PORT
The default port of the STUN server (TCP).
Definition config.h:20
static const uint8_t NETWORK_COORDINATOR_VERSION
What version of game-coordinator-protocol do we use?
Definition config.h:48
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition core.h:21
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition core.h:22
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
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.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
@ SPS_ALL_SENT
All packets in the queue are sent.
Definition tcp.h:25
@ PACKET_STUN_SERCLI_STUN
Send a STUN request to the STUN server.
Definition tcp_stun.h:19