summaryrefslogtreecommitdiff
path: root/src/network/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/core')
-rw-r--r--src/network/core/CMakeLists.txt2
-rw-r--r--src/network/core/address.cpp42
-rw-r--r--src/network/core/address.h2
-rw-r--r--src/network/core/config.cpp14
-rw-r--r--src/network/core/config.h4
-rw-r--r--src/network/core/os_abstraction.cpp17
-rw-r--r--src/network/core/os_abstraction.h1
-rw-r--r--src/network/core/tcp.h3
-rw-r--r--src/network/core/tcp_connect.cpp12
-rw-r--r--src/network/core/tcp_coordinator.cpp6
-rw-r--r--src/network/core/tcp_coordinator.h48
-rw-r--r--src/network/core/tcp_listen.h72
-rw-r--r--src/network/core/tcp_stun.cpp29
-rw-r--r--src/network/core/tcp_stun.h53
14 files changed, 257 insertions, 48 deletions
diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt
index 82bf7843d..bcecad38c 100644
--- a/src/network/core/CMakeLists.txt
+++ b/src/network/core/CMakeLists.txt
@@ -28,6 +28,8 @@ add_files(
tcp_http.cpp
tcp_http.h
tcp_listen.h
+ tcp_stun.cpp
+ tcp_stun.h
udp.cpp
udp.h
)
diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp
index 4c090c14a..9a2d3dc48 100644
--- a/src/network/core/address.cpp
+++ b/src/network/core/address.cpp
@@ -313,13 +313,12 @@ static SOCKET ListenLoopProc(addrinfo *runp)
Debug(net, 1, "Setting no-delay mode failed: {}", NetworkError::GetLast().AsString());
}
- int on = 1;
- /* The (const char*) cast is needed for windows!! */
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) {
+ if (!SetReusePort(sock)) {
Debug(net, 0, "Setting reuse-address mode failed: {}", NetworkError::GetLast().AsString());
}
#ifndef __OS2__
+ int on = 1;
if (runp->ai_family == AF_INET6 &&
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) {
Debug(net, 3, "Could not disable IPv4 over IPv6: {}", NetworkError::GetLast().AsString());
@@ -401,16 +400,45 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
}
/**
+ * Get the peer address of a socket as NetworkAddress.
+ * @param sock The socket to get the peer address of.
+ * @return The NetworkAddress of the peer address.
+ */
+/* static */ NetworkAddress NetworkAddress::GetPeerAddress(SOCKET sock)
+{
+ sockaddr_storage addr = {};
+ socklen_t addr_len = sizeof(addr);
+ if (getpeername(sock, (sockaddr *)&addr, &addr_len) != 0) {
+ Debug(net, 0, "Failed to get address of the peer: {}", NetworkError::GetLast().AsString());
+ return NetworkAddress();
+ }
+ return NetworkAddress(addr, addr_len);
+}
+
+/**
+ * Get the local address of a socket as NetworkAddress.
+ * @param sock The socket to get the local address of.
+ * @return The NetworkAddress of the local address.
+ */
+/* static */ NetworkAddress NetworkAddress::GetSockAddress(SOCKET sock)
+{
+ sockaddr_storage addr = {};
+ socklen_t addr_len = sizeof(addr);
+ if (getsockname(sock, (sockaddr *)&addr, &addr_len) != 0) {
+ Debug(net, 0, "Failed to get address of the socket: {}", NetworkError::GetLast().AsString());
+ return NetworkAddress();
+ }
+ return NetworkAddress(addr, addr_len);
+}
+
+/**
* Get the peer name of a socket in string format.
* @param sock The socket to get the peer name of.
* @return The string representation of the peer name.
*/
/* static */ const std::string NetworkAddress::GetPeerName(SOCKET sock)
{
- sockaddr_storage addr;
- socklen_t addr_len = sizeof(addr);
- getpeername(sock, (sockaddr *)&addr, &addr_len);
- return NetworkAddress(addr, addr_len).GetAddressAsString();
+ return NetworkAddress::GetPeerAddress(sock).GetAddressAsString();
}
/**
diff --git a/src/network/core/address.h b/src/network/core/address.h
index 9e09632d3..f9c2eaef6 100644
--- a/src/network/core/address.h
+++ b/src/network/core/address.h
@@ -175,6 +175,8 @@ public:
static const char *SocketTypeAsString(int socktype);
static const char *AddressFamilyAsString(int family);
+ static NetworkAddress GetPeerAddress(SOCKET sock);
+ static NetworkAddress GetSockAddress(SOCKET sock);
static const std::string GetPeerName(SOCKET sock);
};
diff --git a/src/network/core/config.cpp b/src/network/core/config.cpp
index c5fe3adbd..6e7f8a11c 100644
--- a/src/network/core/config.cpp
+++ b/src/network/core/config.cpp
@@ -39,9 +39,19 @@ const char *NetworkCoordinatorConnectionString()
}
/**
+ * Get the connection string for the STUN server from the environment variable OTTD_STUN_CS,
+ * or when it has not been set a hard coded default DNS hostname of the production server.
+ * @return The STUN server's connection string.
+ */
+const char *NetworkStunConnectionString()
+{
+ return GetEnv("OTTD_STUN_CS", "stun.openttd.org");
+}
+
+/**
* Get the connection string for the content server from the environment variable OTTD_CONTENT_SERVER_CS,
* or when it has not been set a hard coded default DNS hostname of the production server.
- * @return The game coordinator's connection string.
+ * @return The content server's connection string.
*/
const char *NetworkContentServerConnectionString()
{
@@ -51,7 +61,7 @@ const char *NetworkContentServerConnectionString()
/**
* Get the connection string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_CS,
* or when it has not been set a hard coded default DNS hostname of the production server.
- * @return The game coordinator's connection string.
+ * @return The content mirror's connection string.
*/
const char *NetworkContentMirrorConnectionString()
{
diff --git a/src/network/core/config.h b/src/network/core/config.h
index 757556993..6039c4252 100644
--- a/src/network/core/config.h
+++ b/src/network/core/config.h
@@ -13,6 +13,7 @@
#define NETWORK_CORE_CONFIG_H
const char *NetworkCoordinatorConnectionString();
+const char *NetworkStunConnectionString();
const char *NetworkContentServerConnectionString();
const char *NetworkContentMirrorConnectionString();
@@ -20,6 +21,7 @@ const char *NetworkContentMirrorConnectionString();
static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas";
static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP)
+static const uint16 NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP)
static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP)
static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP)
static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
@@ -47,7 +49,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe
static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use?
static const byte NETWORK_GAME_INFO_VERSION = 5; ///< What version of game-info do we use?
static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this?
-static const byte NETWORK_COORDINATOR_VERSION = 2; ///< What version of game-coordinator-protocol do we use?
+static const byte NETWORK_COORDINATOR_VERSION = 3; ///< What version of game-coordinator-protocol do we use?
static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0'
static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0'
diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp
index 202806a34..225c95d93 100644
--- a/src/network/core/os_abstraction.cpp
+++ b/src/network/core/os_abstraction.cpp
@@ -160,6 +160,23 @@ bool SetNoDelay(SOCKET d)
}
/**
+ * Try to set the socket to reuse ports.
+ * @param d The socket to reuse ports on.
+ * @return True if disabling the delaying succeeded, otherwise false.
+ */
+bool SetReusePort(SOCKET d)
+{
+#ifdef _WIN32
+ /* Windows has no SO_REUSEPORT, but for our usecases SO_REUSEADDR does the same job. */
+ int reuse_port = 1;
+ return setsockopt(d, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_port, sizeof(reuse_port)) == 0;
+#else
+ int reuse_port = 1;
+ return setsockopt(d, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port)) == 0;
+#endif
+}
+
+/**
* Get the error from a socket, if any.
* @param d The socket to get the error from.
* @return The errno on the socket.
diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h
index fbde92c05..6bb6101a1 100644
--- a/src/network/core/os_abstraction.h
+++ b/src/network/core/os_abstraction.h
@@ -196,6 +196,7 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address
bool SetNonBlocking(SOCKET d);
bool SetNoDelay(SOCKET d);
+bool SetReusePort(SOCKET d);
NetworkError GetSocketError(SOCKET d);
/* Make sure these structures have the size we expect them to be */
diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h
index b4b4398de..52d9cfddb 100644
--- a/src/network/core/tcp.h
+++ b/src/network/core/tcp.h
@@ -99,6 +99,7 @@ private:
std::string connection_string; ///< Current address we are connecting to (before resolving).
NetworkAddress bind_address; ///< Address we're binding to, if any.
+ int family = AF_UNSPEC; ///< Family we are using to connect with.
void Resolve();
void OnResolved(addrinfo *ai);
@@ -114,7 +115,7 @@ private:
public:
TCPConnecter() {};
- TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {});
+ TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {}, int family = AF_UNSPEC);
virtual ~TCPConnecter();
/**
diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp
index 6db2500f3..29e9048d9 100644
--- a/src/network/core/tcp_connect.cpp
+++ b/src/network/core/tcp_connect.cpp
@@ -29,8 +29,9 @@ static std::vector<TCPConnecter *> _tcp_connecters;
* @param default_port If not indicated in connection_string, what port to use.
* @param bind_address The local bind address to use. Defaults to letting the OS find one.
*/
-TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address) :
- bind_address(bind_address)
+TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address, int family) :
+ bind_address(bind_address),
+ family(family)
{
this->connection_string = NormalizeConnectionString(connection_string, default_port);
@@ -99,6 +100,10 @@ void TCPConnecter::Connect(addrinfo *address)
return;
}
+ if (!SetReusePort(sock)) {
+ Debug(net, 0, "Setting reuse-port mode failed: {}", NetworkError::GetLast().AsString());
+ }
+
if (this->bind_address.GetPort() > 0) {
if (bind(sock, (const sockaddr *)this->bind_address.GetAddress(), this->bind_address.GetAddressLength()) != 0) {
Debug(net, 1, "Could not bind socket on {}: {}", this->bind_address.GetAddressAsString(), NetworkError::GetLast().AsString());
@@ -170,6 +175,9 @@ void TCPConnecter::OnResolved(addrinfo *ai)
/* Convert the addrinfo into NetworkAddresses. */
for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) {
+ /* Skip entries if the family is set and it is not matching. */
+ if (this->family != AF_UNSPEC && this->family != runp->ai_family) continue;
+
if (resort) {
if (runp->ai_family == AF_INET6) {
addresses_ipv6.emplace_back(runp);
diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp
index dfd73147e..abcff9579 100644
--- a/src/network/core/tcp_coordinator.cpp
+++ b/src/network/core/tcp_coordinator.cpp
@@ -39,6 +39,9 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p)
case PACKET_COORDINATOR_GC_CONNECT_FAILED: return this->Receive_GC_CONNECT_FAILED(p);
case PACKET_COORDINATOR_CLIENT_CONNECTED: return this->Receive_CLIENT_CONNECTED(p);
case PACKET_COORDINATOR_GC_DIRECT_CONNECT: return this->Receive_GC_DIRECT_CONNECT(p);
+ case PACKET_COORDINATOR_GC_STUN_REQUEST: return this->Receive_GC_STUN_REQUEST(p);
+ case PACKET_COORDINATOR_SERCLI_STUN_RESULT: return this->Receive_SERCLI_STUN_RESULT(p);
+ case PACKET_COORDINATOR_GC_STUN_CONNECT: return this->Receive_GC_STUN_CONNECT(p);
default:
Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type);
@@ -94,3 +97,6 @@ bool NetworkCoordinatorSocketHandler::Receive_SERCLI_CONNECT_FAILED(Packet *p) {
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECT_FAILED); }
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECTED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECTED); }
bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_DIRECT_CONNECT); }
+bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_REQUEST); }
+bool NetworkCoordinatorSocketHandler::Receive_SERCLI_STUN_RESULT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_STUN_RESULT); }
+bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_CONNECT); }
diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h
index 2d793b1b6..40502e7e3 100644
--- a/src/network/core/tcp_coordinator.h
+++ b/src/network/core/tcp_coordinator.h
@@ -38,6 +38,9 @@ enum PacketCoordinatorType {
PACKET_COORDINATOR_GC_CONNECT_FAILED, ///< Game Coordinator informs client/server it has given up on the connection attempt.
PACKET_COORDINATOR_CLIENT_CONNECTED, ///< Client informs the Game Coordinator the connection with the server is established.
PACKET_COORDINATOR_GC_DIRECT_CONNECT, ///< Game Coordinator tells client to directly connect to the hostname:port of the server.
+ PACKET_COORDINATOR_GC_STUN_REQUEST, ///< Game Coordinator tells client/server to initiate a STUN request.
+ PACKET_COORDINATOR_SERCLI_STUN_RESULT, ///< Client/server informs the Game Coordinator of the result of the STUN request.
+ PACKET_COORDINATOR_GC_STUN_CONNECT, ///< Game Coordinator tells client/server to connect() reusing the STUN local address.
PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period)
};
@@ -48,6 +51,7 @@ enum ConnectionType {
CONNECTION_TYPE_UNKNOWN, ///< The Game Coordinator hasn't informed us yet what type of connection we have.
CONNECTION_TYPE_ISOLATED, ///< The Game Coordinator failed to find a way to connect to your server. Nobody will be able to join.
CONNECTION_TYPE_DIRECT, ///< The Game Coordinator can directly connect to your server.
+ CONNECTION_TYPE_STUN, ///< The Game Coordinator can connect to your server via a STUN request.
};
/**
@@ -215,6 +219,50 @@ protected:
*/
virtual bool Receive_GC_DIRECT_CONNECT(Packet *p);
+ /**
+ * Game Coordinator requests the client/server to do a STUN request to the
+ * STUN server. Important is to remember the local port these STUN requests
+ * are sent from, as this will be needed for later conenctions too.
+ * The client/server should do multiple STUN requests for every available
+ * interface that connects to the Internet (e.g., once for IPv4 and once
+ * for IPv6).
+ *
+ * string Token to track the current connect request.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_GC_STUN_REQUEST(Packet *p);
+
+ /**
+ * Client/server informs the Game Coordinator the result of a STUN request.
+ *
+ * uint8 Game Coordinator protocol version.
+ * string Token to track the current connect request.
+ * uint8 Interface number, as given during STUN request.
+ * bool Whether the STUN connection was successful.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_SERCLI_STUN_RESULT(Packet *p);
+
+ /**
+ * Game Coordinator informs the client/server of its STUN peer (the host:ip
+ * of the other side). It should start a connect() to this peer ASAP with
+ * the local address as used with the STUN request.
+ *
+ * string Token to track the current connect request.
+ * uint8 Tracking number to track current connect request.
+ * uint8 Interface number, as given during STUN request.
+ * string Host of the peer.
+ * uint16 Port of the peer.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_GC_STUN_CONNECT(Packet *p);
+
bool HandlePacket(Packet *p);
public:
/**
diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h
index 03945e230..0c7b11df1 100644
--- a/src/network/core/tcp_listen.h
+++ b/src/network/core/tcp_listen.h
@@ -30,6 +30,42 @@ class TCPListenHandler {
static SocketList sockets;
public:
+ static bool ValidateClient(SOCKET s, NetworkAddress &address)
+ {
+ /* Check if the client is banned. */
+ for (const auto &entry : _network_ban_list) {
+ if (address.IsInNetmask(entry)) {
+ Packet p(Tban_packet);
+ p.PrepareToSend();
+
+ Debug(net, 2, "[{}] Banned ip tried to join ({}), refused", Tsocket::GetName(), entry);
+
+ if (p.TransferOut<int>(send, s, 0) < 0) {
+ Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString());
+ }
+ closesocket(s);
+ return false;
+ }
+ }
+
+ /* Can we handle a new client? */
+ if (!Tsocket::AllowConnection()) {
+ /* No more clients allowed?
+ * Send to the client that we are full! */
+ Packet p(Tfull_packet);
+ p.PrepareToSend();
+
+ if (p.TransferOut<int>(send, s, 0) < 0) {
+ Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString());
+ }
+ closesocket(s);
+
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Accepts clients from the sockets.
* @param ls Socket to accept clients from.
@@ -53,41 +89,7 @@ public:
SetNoDelay(s); // XXX error handling?
- /* Check if the client is banned */
- bool banned = false;
- for (const auto &entry : _network_ban_list) {
- banned = address.IsInNetmask(entry);
- if (banned) {
- Packet p(Tban_packet);
- p.PrepareToSend();
-
- Debug(net, 2, "[{}] Banned ip tried to join ({}), refused", Tsocket::GetName(), entry);
-
- if (p.TransferOut<int>(send, s, 0) < 0) {
- Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString());
- }
- closesocket(s);
- break;
- }
- }
- /* If this client is banned, continue with next client */
- if (banned) continue;
-
- /* Can we handle a new client? */
- if (!Tsocket::AllowConnection()) {
- /* no more clients allowed?
- * Send to the client that we are full! */
- Packet p(Tfull_packet);
- p.PrepareToSend();
-
- if (p.TransferOut<int>(send, s, 0) < 0) {
- Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString());
- }
- closesocket(s);
-
- continue;
- }
-
+ if (!Tsocket::ValidateClient(s, address)) continue;
Tsocket::AcceptConnection(s, address);
}
}
diff --git a/src/network/core/tcp_stun.cpp b/src/network/core/tcp_stun.cpp
new file mode 100644
index 000000000..b6aeff683
--- /dev/null
+++ b/src/network/core/tcp_stun.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 tcp_stun.cpp Basic functions to receive and send STUN packets.
+ */
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "tcp_stun.h"
+
+#include "../../safeguards.h"
+
+/**
+ * Helper for logging receiving invalid packets.
+ * @param type The received packet type.
+ * @return Always false, as it's an error.
+ */
+bool NetworkStunSocketHandler::ReceiveInvalidPacket(PacketStunType type)
+{
+ Debug(net, 0, "[tcp/stun] Received illegal packet type {}", type);
+ return false;
+}
+
+bool NetworkStunSocketHandler::Receive_SERCLI_STUN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_STUN_SERCLI_STUN); }
diff --git a/src/network/core/tcp_stun.h b/src/network/core/tcp_stun.h
new file mode 100644
index 000000000..e96a97ef3
--- /dev/null
+++ b/src/network/core/tcp_stun.h
@@ -0,0 +1,53 @@
+/*
+ * 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 tcp_stun.h Basic functions to receive and send TCP packets to/from the STUN server.
+ */
+
+#ifndef NETWORK_CORE_TCP_STUN_H
+#define NETWORK_CORE_TCP_STUN_H
+
+#include "os_abstraction.h"
+#include "tcp.h"
+#include "packet.h"
+
+/** Enum with all types of TCP STUN packets. The order MUST not be changed. **/
+enum PacketStunType {
+ PACKET_STUN_SERCLI_STUN, ///< Send a STUN request to the STUN server.
+ PACKET_STUN_END, ///< Must ALWAYS be on the end of this list!! (period)
+};
+
+/** Base socket handler for all STUN TCP sockets. */
+class NetworkStunSocketHandler : public NetworkTCPSocketHandler {
+protected:
+ bool ReceiveInvalidPacket(PacketStunType type);
+
+ /**
+ * Send a STUN request to the STUN server letting the Game Coordinator know
+ * what our actually public IP:port is.
+ *
+ * uint8 Game Coordinator protocol version.
+ * string Token to track the current STUN request.
+ * uint8 Which interface number this is (for example, IPv4 or IPv6).
+ * The Game Coordinator relays this number back in later packets.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_SERCLI_STUN(Packet *p);
+
+public:
+ /**
+ * Create a new cs socket handler for a given cs.
+ * @param s the socket we are connected with.
+ * @param address IP etc. of the client.
+ */
+ NetworkStunSocketHandler(SOCKET s = INVALID_SOCKET) : NetworkTCPSocketHandler(s) {}
+};
+
+#endif /* NETWORK_CORE_TCP_STUN_H */