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/>.
8 /** @file network_stun.cpp STUN sending/receiving part of the network protocol. */
10 #include "../stdafx.h"
13 #include "network_coordinator.h"
14 #include "network_stun.h"
16 #include "../safeguards.h"
18 /** Connect to the STUN server. */
19 class NetworkStunConnecter
: public TCPConnecter
{
21 ClientNetworkStunSocketHandler
*stun_handler
;
27 * Initiate the connecting.
28 * @param stun_handler The handler for this request.
29 * @param connection_string The address of the server.
31 NetworkStunConnecter(ClientNetworkStunSocketHandler
*stun_handler
, const std::string
&connection_string
, const std::string
&token
, uint8 family
) :
32 TCPConnecter(connection_string
, NETWORK_STUN_SERVER_PORT
, NetworkAddress(), family
),
33 stun_handler(stun_handler
),
39 void OnFailure() override
41 this->stun_handler
->connecter
= nullptr;
43 /* Connection to STUN server failed. For example, the client doesn't
44 * support IPv6, which means it will fail that attempt. */
46 _network_coordinator_client
.StunResult(this->token
, this->family
, false);
49 void OnConnect(SOCKET s
) override
51 this->stun_handler
->connecter
= nullptr;
53 assert(this->stun_handler
->sock
== INVALID_SOCKET
);
54 this->stun_handler
->sock
= s
;
56 /* Store the local address; later connects will reuse it again.
57 * This is what makes STUN work for most NATs. */
58 this->stun_handler
->local_addr
= NetworkAddress::GetSockAddress(s
);
60 /* We leave the connection open till the real connection is setup later. */
65 * Connect to the STUN server over either IPv4 or IPv6.
66 * @param token The token as received from the Game Coordinator.
67 * @param family What IP family to use.
69 void ClientNetworkStunSocketHandler::Connect(const std::string
&token
, uint8 family
)
72 this->family
= family
;
74 this->connecter
= new NetworkStunConnecter(this, NetworkStunConnectionString(), token
, family
);
78 * Send a STUN packet to the STUN server.
79 * @param token The token as received from the Game Coordinator.
80 * @param family What IP family this STUN request is for.
81 * @return The handler for this STUN request.
83 std::unique_ptr
<ClientNetworkStunSocketHandler
> ClientNetworkStunSocketHandler::Stun(const std::string
&token
, uint8 family
)
85 auto stun_handler
= std::make_unique
<ClientNetworkStunSocketHandler
>();
87 stun_handler
->Connect(token
, family
);
89 Packet
*p
= new Packet(PACKET_STUN_SERCLI_STUN
);
90 p
->Send_uint8(NETWORK_COORDINATOR_VERSION
);
91 p
->Send_string(token
);
92 p
->Send_uint8(family
);
94 stun_handler
->SendPacket(p
);
99 NetworkRecvStatus
ClientNetworkStunSocketHandler::CloseConnection(bool error
)
101 NetworkStunSocketHandler::CloseConnection(error
);
103 /* If our connecter is still pending, shut it down too. Otherwise the
104 * callback of the connecter can call into us, and our object is most
105 * likely about to be destroyed. */
106 if (this->connecter
!= nullptr) {
107 this->connecter
->Kill();
108 this->connecter
= nullptr;
111 return NETWORK_RECV_STATUS_OKAY
;
115 * Check whether we received/can send some data from/to the STUN server and
116 * when that's the case handle it appropriately.
118 void ClientNetworkStunSocketHandler::SendReceive()
120 if (this->sock
== INVALID_SOCKET
) return;
122 /* We never attempt to receive anything on a STUN socket. After
123 * connecting a STUN connection, the local address will be reused to
124 * to establish the connection with the real server. If we would be to
125 * read this socket, some OSes get confused and deliver us packets meant
126 * for the real connection. It appears most OSes play best when we simply
127 * never attempt to read it to start with (and the packets will remain
128 * available on the other socket).
129 * Protocol-wise, the STUN server will never send any packet back anyway. */
131 this->CanSendReceive();
132 if (this->SendPackets() == SPS_ALL_SENT
&& !this->sent_result
) {
133 /* We delay giving the GC the result this long, as to make sure we
134 * have sent the STUN packet first. This means the GC is more likely
135 * to have the result ready by the time our StunResult() packet
137 this->sent_result
= true;
138 _network_coordinator_client
.StunResult(this->token
, this->family
, true);