Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: play easier together with friends from behind home routers #9017

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/console_cmds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ DEF_CONSOLE_CMD(ConServerInfo)
return true;
}

IConsolePrint(CC_DEFAULT, "Invite code: {}", _network_game_info.join_key);
IConsolePrint(CC_DEFAULT, "Current/maximum clients: {:3d}/{:3d}", _network_game_info.clients_on, _settings_client.network.max_clients);
IConsolePrint(CC_DEFAULT, "Current/maximum companies: {:3d}/{:3d}", Company::GetNumItems(), _settings_client.network.max_companies);
IConsolePrint(CC_DEFAULT, "Current/maximum spectators: {:3d}/{:3d}", NetworkSpectatorCount(), _settings_client.network.max_spectators);
Expand Down Expand Up @@ -2419,7 +2420,6 @@ void IConsoleStdLibRegister()
IConsole::AliasRegister("name", "setting client_name %+");
IConsole::AliasRegister("server_name", "setting server_name %+");
IConsole::AliasRegister("server_port", "setting server_port %+");
IConsole::AliasRegister("server_advertise", "setting server_advertise %+");
IConsole::AliasRegister("max_clients", "setting max_clients %+");
IConsole::AliasRegister("max_companies", "setting max_companies %+");
IConsole::AliasRegister("max_spectators", "setting max_spectators %+");
Expand Down
26 changes: 23 additions & 3 deletions src/lang/english.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1995,8 +1995,11 @@ STR_FACE_TIE :Tie:
STR_FACE_EARRING :Earring:
STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring

STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Private
############ Next lines match ServerGameType
STR_NETWORK_SERVER_VISIBILITY_LOCAL :Local
STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public
STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY :Invite only
############ End of leave-in-this-order

# Network server list
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer
Expand Down Expand Up @@ -2030,6 +2033,7 @@ STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Server
STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Server address: {WHITE}{RAW_STRING}
STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Start date: {WHITE}{DATE_SHORT}
STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Current date: {WHITE}{DATE_SHORT}
STR_NETWORK_SERVER_LIST_GAMESCRIPT :{SILVER}Gamescript: {WHITE}{RAW_STRING} (v{NUM})
STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Password protected!
STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE
STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER FULL
Expand All @@ -2045,12 +2049,12 @@ STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Search i
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Search LAN
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Search local area network for servers
STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Add server
STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list which will always be checked for running games
STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list. This can either be a server address or an invite-code
STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Start server
STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Start your own server

STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Enter your name
STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Enter the address of the host
STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS :{BLACK}Enter server address or invite-code

# Start new multiplayer server
STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start new multiplayer game
Expand Down Expand Up @@ -2136,6 +2140,10 @@ STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edit the
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name of the server
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibility
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing
STR_NETWORK_CLIENT_LIST_SERVER_JOIN_KEY :{BLACK}Invite code
STR_NETWORK_CLIENT_LIST_SERVER_JOIN_KEY_TOOLTIP :{BLACK}Invite code other players can use to join this server
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE :{BLACK}Connection type
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP :{BLACK}Whether and how your server can be reached by others
STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Player
STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Name
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Your player name
Expand All @@ -2154,6 +2162,14 @@ STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game
STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies}

############ Begin of ConnectionType
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN :{BLACK}Local
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_ISOLATED :{RED}Remote players can't connect
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_DIRECT :{BLACK}Public
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_STUN :{BLACK}Behind NAT
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TURN :{BLACK}Via relay
############ End of ConnectionType

STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Kick
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Ban
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Delete
Expand Down Expand Up @@ -2281,6 +2297,10 @@ STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The serv
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait...
STR_NETWORK_MESSAGE_KICKED :*** {RAW_STRING} was kicked. Reason: ({RAW_STRING})

STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Server registration failed
STR_NETWORK_ERROR_COORDINATOR_ISOLATED :{WHITE}Your server doesn't allow remote connections
STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL :{WHITE}Other players won't be able to connect to your server

# Content downloading window
STR_CONTENT_TITLE :{WHITE}Content downloading
STR_CONTENT_TYPE_CAPTION :{BLACK}Type
Expand Down
6 changes: 6 additions & 0 deletions src/network/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ add_files(
network_content.h
network_content_gui.cpp
network_content_gui.h
network_coordinator.cpp
network_coordinator.h
network_func.h
network_gamelist.cpp
network_gamelist.h
Expand All @@ -22,6 +24,10 @@ add_files(
network_internal.h
network_server.cpp
network_server.h
network_stun.cpp
network_stun.h
network_turn.cpp
network_turn.h
network_type.h
network_udp.cpp
network_udp.h
Expand Down
6 changes: 6 additions & 0 deletions src/network/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ add_files(
tcp_content.cpp
tcp_content.h
tcp_content_type.h
tcp_coordinator.cpp
tcp_coordinator.h
tcp_game.cpp
tcp_game.h
tcp_http.cpp
tcp_http.h
tcp_listen.h
tcp_stun.cpp
tcp_stun.h
tcp_turn.cpp
tcp_turn.h
udp.cpp
udp.h
)
65 changes: 58 additions & 7 deletions src/network/core/address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../../stdafx.h"

#include "address.h"
#include "../network_internal.h"
#include "../../debug.h"

#include "../../safeguards.h"
Expand Down Expand Up @@ -312,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());
Expand Down Expand Up @@ -399,15 +399,66 @@ 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();
}

/**
* Convert a string containing either "hostname" or "hostname:ip" to a
* ServerAddress, where the string can be postfixed with "#company" to
* indicate the requested company.
*
* @param connection_string The string to parse.
* @param default_port The default port to set port to if not in connection_string.
* @param company Pointer to the company variable to set iff indicted.
* @return A valid ServerAddress of the parsed information.
*/
/* static */ ServerAddress ServerAddress::Parse(const std::string &connection_string, uint16 default_port, CompanyID *company_id)
{
if (!connection_string.empty() && connection_string[0] == '+') {
std::string_view ip = ParseCompanyFromConnectionString(connection_string, company_id);
return ServerAddress(SERVER_ADDRESS_JOIN_KEY, std::string(ip));
}

uint16 port = default_port;
std::string_view ip = ParseFullConnectionString(connection_string, port, company_id);
return ServerAddress(SERVER_ADDRESS_DIRECT, std::string(ip) + ":" + std::to_string(port));
}
37 changes: 37 additions & 0 deletions src/network/core/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "os_abstraction.h"
#include "config.h"
#include "../../company_type.h"
#include "../../string_func.h"
#include "../../core/smallmap_type.hpp"

Expand Down Expand Up @@ -174,7 +175,43 @@ class NetworkAddress {

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);
};

/**
* Types of server addresses we know.
*
* Sorting will prefer entries at the top of this list above ones at the bottom.
*/
enum ServerAddressType {
SERVER_ADDRESS_DIRECT, ///< Server-address is based on an IP:port.
SERVER_ADDRESS_JOIN_KEY, ///< Server-address is based on a join-key given by the Game Coordinator.
};

/**
* Address to a game server.
*
* This generalises addresses which are based on different identifiers.
*/
class ServerAddress {
private:
/**
* Create a new ServerAddress object.
*
* Please use ServerAddress::Parse() instead of calling this directly.
TrueBrain marked this conversation as resolved.
Show resolved Hide resolved
*
* @param type The type of the ServerAdress.
* @param connection_string The connection_string that belongs to this ServerAddress type.
*/
ServerAddress(ServerAddressType type, const std::string &connection_string) : type(type), connection_string(connection_string) {}

public:
ServerAddressType type; ///< The type of this ServerAddress.
std::string connection_string; ///< The connection string for this ServerAddress.

static ServerAddress Parse(const std::string &connection_string, uint16 default_port, CompanyID *company_id = nullptr);
};

#endif /* NETWORK_CORE_ADDRESS_H */
42 changes: 32 additions & 10 deletions src/network/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

/** DNS hostname of the masterserver */
static const char * const NETWORK_MASTER_SERVER_HOST = "master.openttd.org";
/** DNS hostname of the Game Coordinator server */
static const char * const NETWORK_COORDINATOR_SERVER_HOST = "coordinator.openttd.org";
/** DNS hostname of the STUN server */
static const char * const NETWORK_STUN_SERVER_HOST = "stun.openttd.org";
/** DNS hostname of the content server */
static const char * const NETWORK_CONTENT_SERVER_HOST = "content.openttd.org";
/** DNS hostname of the HTTP-content mirror server */
Expand All @@ -23,14 +27,16 @@ static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas";
/** Message sent to the masterserver to 'identify' this client as OpenTTD */
static const char * const NETWORK_MASTER_SERVER_WELCOME_MESSAGE = "OpenTTDRegister";

static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP)
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)
static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)
static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP)
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)
static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)

static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
/*
* Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future
* to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8.
Expand All @@ -49,9 +55,10 @@ static const uint16 TCP_MTU = 32767; ///< Number of
static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility

static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use?
static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use?
static const byte NETWORK_GAME_INFO_VERSION = 6; ///< 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_MASTER_SERVER_VERSION = 2; ///< What version of master-server-protocol do we use?
static const byte NETWORK_COORDINATOR_VERSION = 1; ///< 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'
Expand All @@ -71,14 +78,29 @@ static const uint NETWORK_CONTENT_VERSION_LENGTH = 16; ///< The maxim
static const uint NETWORK_CONTENT_URL_LENGTH = 96; ///< The maximum length of a content's url, in bytes including '\0'.
static const uint NETWORK_CONTENT_DESC_LENGTH = 512; ///< The maximum length of a content's description, in bytes including '\0'.
static const uint NETWORK_CONTENT_TAG_LENGTH = 32; ///< The maximum length of a content's tag, in bytes including '\0'.
static const uint NETWORK_JOIN_KEY_LENGTH = 64; ///< The maximum length of the join key, in bytes including '\0'
static const uint NETWORK_JOIN_KEY_SECRET_LENGTH = 80; ///< The maximum length of the join key secret, in bytes including '\0'
static const uint NETWORK_ERROR_DETAIL_LENGTH = 100; ///< The maximum length of the error detail, in bytes including '\0'
static const uint NETWORK_TOKEN_LENGTH = 64; ///< The maximum length of a token, in bytes including '\0'

static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF

/**
* Maximum number of GRFs that can be sent.
* This limit is reached when PACKET_UDP_SERVER_RESPONSE reaches the maximum size of UDP_MTU bytes.
*
* This limit exists to avoid that the SERVER_INFO packet exceeding the
* maximum MTU. At the time of writing this limit is 32767 (TCP_MTU).
*
* In the SERVER_INFO packet is the NetworkGameInfo struct, which is
* 142 bytes + 100 per NewGRF (under the assumption strings are used to
* their max). This brings us to roughly 326 possible NewGRFs. Round it
* down so people don't freak out because they see a weird value, and you
* get the limit: 255.
*
* PS: in case you ever want to raise this number, please be mindful that
* "amount of NewGRFs" in NetworkGameInfo is currently an uint8.
*/
static const uint NETWORK_MAX_GRF_COUNT = 62;
static const uint NETWORK_MAX_GRF_COUNT = 255;

/**
* The number of landscapes in OpenTTD.
Expand Down
Loading