summaryrefslogtreecommitdiff
path: root/src/network/network_coordinator.cpp
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2021-05-05 10:47:01 +0200
committerPatric Stout <github@truebrain.nl>2021-07-20 19:57:23 +0200
commitfa1e27994dd1284f6fefbe08c47a5c4145ccf00d (patch)
treebbe8fab946192e5667ef176673590d2fae60e969 /src/network/network_coordinator.cpp
parent8a361340037d6908c9a4df10aefdb58860a22b80 (diff)
downloadopenttd-fa1e27994dd1284f6fefbe08c47a5c4145ccf00d.tar.xz
Feature: allow the use of TURN to connect client and server together
TURN is a last resort, used only if all other methods failed. TURN is a relay approach to connect client and server together, where openttd.org (by default) is the middleman. It is very unlikely either the client or server cannot connect to the STUN server, as they are both already connected to the Game Coordinator. But in the odd case it does fail, estabilishing the connection fails without any further possibility to recover.
Diffstat (limited to 'src/network/network_coordinator.cpp')
-rw-r--r--src/network/network_coordinator.cpp83
1 files changed, 82 insertions, 1 deletions
diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp
index 9fe1e78f0..6456ac9e8 100644
--- a/src/network/network_coordinator.cpp
+++ b/src/network/network_coordinator.cpp
@@ -18,6 +18,7 @@
#include "network.h"
#include "network_coordinator.h"
#include "network_gamelist.h"
+#include "network_gui.h"
#include "network_internal.h"
#include "network_server.h"
#include "network_stun.h"
@@ -193,6 +194,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p)
case CONNECTION_TYPE_ISOLATED: connection_type = "Remote players can't connect"; break;
case CONNECTION_TYPE_DIRECT: connection_type = "Public"; break;
case CONNECTION_TYPE_STUN: connection_type = "Behind NAT"; break;
+ case CONNECTION_TYPE_TURN: connection_type = "Via relay"; break;
case CONNECTION_TYPE_UNKNOWN: // Never returned from Game Coordinator.
default: connection_type = "Unknown"; break; // Should never happen, but don't fail if it does.
@@ -355,6 +357,50 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_NEWGRF_LOOKUP(Packet *p)
return true;
}
+bool ClientNetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet *p)
+{
+ std::string token = p->Recv_string(NETWORK_TOKEN_LENGTH);
+ uint8 tracking_number = p->Recv_uint8();
+ std::string ticket = p->Recv_string(NETWORK_TOKEN_LENGTH);
+ std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
+
+ /* Ensure all other pending connection attempts are killed. */
+ if (this->game_connecter != nullptr) {
+ this->game_connecter->Kill();
+ this->game_connecter = nullptr;
+ }
+
+ this->turn_handlers[token] = ClientNetworkTurnSocketHandler::Turn(token, tracking_number, ticket, connection_string);
+
+ if (!_network_server) {
+ switch (_settings_client.network.use_relay_service) {
+ case URS_NEVER:
+ this->ConnectFailure(token, 0);
+ break;
+
+ case URS_ASK:
+ ShowNetworkAskRelay(connection_string, token);
+ break;
+
+ case URS_ALLOW:
+ this->StartTurnConnection(token);
+ break;
+ }
+ } else {
+ this->StartTurnConnection(token);
+ }
+
+ return true;
+}
+
+void ClientNetworkCoordinatorSocketHandler::StartTurnConnection(std::string &token)
+{
+ auto turn_it = this->turn_handlers.find(token);
+ if (turn_it == this->turn_handlers.end()) return;
+
+ turn_it->second->Connect();
+}
+
void ClientNetworkCoordinatorSocketHandler::Connect()
{
/* We are either already connected or are trying to connect. */
@@ -580,13 +626,33 @@ void ClientNetworkCoordinatorSocketHandler::CloseStunHandler(const std::string &
}
/**
+ * Close the TURN handler.
+ * @param token The token used for the TURN handler.
+ */
+void ClientNetworkCoordinatorSocketHandler::CloseTurnHandler(const std::string &token)
+{
+ CloseWindowByClass(WC_NETWORK_ASK_RELAY);
+
+ auto turn_it = this->turn_handlers.find(token);
+ if (turn_it == this->turn_handlers.end()) return;
+
+ turn_it->second->CloseConnection();
+ turn_it->second->CloseSocket();
+
+ /* We don't remove turn_handler here, as we can be called from within that
+ * turn_handler instance, so our object cannot be free'd yet. Instead, we
+ * check later if the connection is closed, and free the object then. */
+}
+
+/**
* Close everything related to this connection token.
* @param token The connection token to close.
*/
void ClientNetworkCoordinatorSocketHandler::CloseToken(const std::string &token)
{
- /* Close all remaining STUN connections. */
+ /* Close all remaining STUN / TURN connections. */
this->CloseStunHandler(token);
+ this->CloseTurnHandler(token);
/* Close the caller of the connection attempt. */
auto connecter_it = this->connecter.find(token);
@@ -610,12 +676,14 @@ void ClientNetworkCoordinatorSocketHandler::CloseAllConnections()
/* Mark any pending connecters as failed. */
for (auto &[token, it] : this->connecter) {
this->CloseStunHandler(token);
+ this->CloseTurnHandler(token);
it->SetFailure();
/* Inform the Game Coordinator he can stop trying to connect us to the server. */
this->ConnectFailure(token, 0);
}
this->stun_handlers.clear();
+ this->turn_handlers.clear();
this->connecter.clear();
/* Also close any pending invite-code requests. */
@@ -697,4 +765,17 @@ void ClientNetworkCoordinatorSocketHandler::SendReceive()
stun_handler->SendReceive();
}
}
+
+ /* Check for handlers that are not connecting nor connected. Destroy those objects. */
+ for (auto turn_it = this->turn_handlers.begin(); turn_it != this->turn_handlers.end(); /* nothing */) {
+ if (turn_it->second->connect_started && turn_it->second->connecter == nullptr && !turn_it->second->IsConnected()) {
+ turn_it = this->turn_handlers.erase(turn_it);
+ } else {
+ turn_it++;
+ }
+ }
+
+ for (const auto &[token, turn_handler] : this->turn_handlers) {
+ turn_handler->SendReceive();
+ }
}