Change: use TCP for everything except for master-server and initial server scan (#9130)

This means that pressing Refresh button and adding servers manually
now uses TCP.

The master-server and initial scan are still UDP as they will be
replaced by Game Coordinator; no need to change this now.

If we query a server that is too old, show a proper warning to the
user informing him the server is too old.
This commit is contained in:
Patric Stout 2021-04-30 11:34:47 +02:00 committed by GitHub
parent f00564eeb2
commit 69118d063f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 43 deletions

View File

@ -65,10 +65,14 @@ Module.preRun.push(function() {
}
window.openttd_server_list = function() {
add_server = Module.cwrap("em_openttd_add_server", null, ["string", "number"]);
add_server = Module.cwrap("em_openttd_add_server", null, ["string"]);
/* Add servers that support WebSocket here. Example:
* add_server("localhost", 3979); */
/* Add servers that support WebSocket here. Examples:
* add_server("localhost");
* add_server("localhost:3979");
* add_server("127.0.0.1:3979");
* add_server("[::1]:3979");
*/
}
var leftButtonDown = false;

View File

@ -2217,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your com
STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server
STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your player name is not valid
STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}The queried server is too old for this client
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :general error

View File

@ -602,8 +602,11 @@ static void NetworkInitialize(bool close_admins = true)
/** Non blocking connection create to query servers */
class TCPQueryConnecter : TCPConnecter {
private:
bool request_company_info;
public:
TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
TCPQueryConnecter(const NetworkAddress &address, bool request_company_info) : TCPConnecter(address), request_company_info(request_company_info) {}
void OnFailure() override
{
@ -613,36 +616,53 @@ public:
void OnConnect(SOCKET s) override
{
_networking = true;
new ClientNetworkGameSocketHandler(s);
MyClient::SendInformationQuery();
new ClientNetworkGameSocketHandler(s, address);
MyClient::SendInformationQuery(request_company_info);
}
};
/**
* Query a server to fetch his game-info.
* @param address the address to query.
* @param request_company_info Whether to request company info too.
*/
void NetworkTCPQueryServer(NetworkAddress address)
void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info)
{
if (!_network_available) return;
NetworkDisconnect();
NetworkInitialize();
new TCPQueryConnecter(address);
new TCPQueryConnecter(address, request_company_info);
}
/**
* Validates an address entered as a string and adds the server to
* the list. If you use this function, the games will be marked
* as manually added.
* @param connection_string The IP:port to add to the list.
* @param connection_string The IP:port of the server to add.
* @return The entry on the game list.
*/
void NetworkAddServer(const char *connection_string)
NetworkGameList *NetworkAddServer(const std::string &connection_string)
{
if (StrEmpty(connection_string)) return;
if (connection_string.empty()) return nullptr;
NetworkUDPQueryServer(ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT), true);
NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT);
/* Ensure the item already exists in the list */
NetworkGameList *item = NetworkGameListAddItem(address);
if (StrEmpty(item->info.server_name)) {
ClearGRFConfigList(&item->info.grfconfig);
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
item->manually = true;
NetworkRebuildHostList();
UpdateNetworkGameWindow();
}
NetworkTCPQueryServer(address);
return item;
}
/**
@ -687,7 +707,7 @@ public:
void OnConnect(SOCKET s) override
{
_networking = true;
new ClientNetworkGameSocketHandler(s);
new ClientNetworkGameSocketHandler(s, this->address);
IConsoleCmdExec("exec scripts/on_client.scr 0");
NetworkClient_Connected();
}
@ -1132,9 +1152,9 @@ void NetworkShutDown()
#ifdef __EMSCRIPTEN__
extern "C" {
void CDECL em_openttd_add_server(const char *host, int port)
void CDECL em_openttd_add_server(const char *connection_string)
{
NetworkUDPQueryServer(NetworkAddress(host, port), true);
NetworkAddServer(connection_string);
}
}

View File

@ -145,7 +145,7 @@ void ClientNetworkEmergencySave()
* Create a new socket for the client side of the game connection.
* @param s The socket to connect with.
*/
ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(nullptr), status(STATUS_INACTIVE)
ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address) : NetworkGameSocketHandler(s), address(address), savegame(nullptr), status(STATUS_INACTIVE)
{
assert(ClientNetworkGameSocketHandler::my_client == nullptr);
ClientNetworkGameSocketHandler::my_client = this;
@ -345,14 +345,18 @@ static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
/**
* Query the server for server information.
*/
NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery()
NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery(bool request_company_info)
{
my_client->status = STATUS_COMPANY_INFO;
_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
my_client->status = STATUS_GAME_INFO;
my_client->SendPacket(new Packet(PACKET_CLIENT_GAME_INFO));
my_client->SendPacket(new Packet(PACKET_CLIENT_COMPANY_INFO));
if (request_company_info) {
my_client->status = STATUS_COMPANY_INFO;
_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
my_client->SendPacket(new Packet(PACKET_CLIENT_COMPANY_INFO));
}
return NETWORK_RECV_STATUS_OKAY;
}
@ -577,9 +581,13 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p)
{
if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_INACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_GAME_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
NetworkGameList *item = GetLobbyGameInfo();
if (item == nullptr) {
/* This is not the lobby, so add it to the game list. */
item = NetworkGameListAddItem(this->address);
}
/* Clear any existing GRFConfig chain. */
ClearGRFConfigList(&item->info.grfconfig);
@ -590,6 +598,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packe
/* Ensure we consider the server online. */
item->online = true;
/* It could be either window, but only one is open, so redraw both. */
SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
/* We will receive company info next, so keep connection open. */
@ -727,6 +737,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8();
/* If we query a server that is 1.11.1 or older, we get an
* NETWORK_ERROR_NOT_EXPECTED on requesting the game info. Show a special
* error popup in that case.
*/
if (error == NETWORK_ERROR_NOT_EXPECTED && (this->status == STATUS_GAME_INFO || this->status == STATUS_COMPANY_INFO)) {
ShowErrorMessage(STR_NETWORK_ERROR_SERVER_TOO_OLD, INVALID_STRING_ID, WL_CRITICAL);
return NETWORK_RECV_STATUS_CLOSE_QUERY;
}
StringID err = STR_NETWORK_ERROR_LOSTCONNECTION;
if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
/* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */

View File

@ -15,12 +15,14 @@
/** Class for handling the client side of the game connection. */
class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler {
private:
NetworkAddress address; ///< Address we are connected to.
struct PacketReader *savegame; ///< Packet reader for reading the savegame.
byte token; ///< The token we need to send back to the server to prove we're the right client.
/** Status of the connection with the server. */
enum ServerStatus {
STATUS_INACTIVE, ///< The client is not connected nor active.
STATUS_GAME_INFO, ///< We are trying to get the game information.
STATUS_COMPANY_INFO, ///< We are trying to get company information.
STATUS_JOIN, ///< We are trying to join a server.
STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs.
@ -74,13 +76,13 @@ protected:
static NetworkRecvStatus SendMapOk();
void CheckConnection();
public:
ClientNetworkGameSocketHandler(SOCKET s);
ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address);
~ClientNetworkGameSocketHandler();
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override;
void ClientError(NetworkRecvStatus res);
static NetworkRecvStatus SendInformationQuery();
static NetworkRecvStatus SendInformationQuery(bool request_company_info);
static NetworkRecvStatus SendJoin();
static NetworkRecvStatus SendCommand(const CommandPacket *cp);

View File

@ -69,15 +69,6 @@ static void NetworkGameListHandleDelayedInsert()
*/
NetworkGameList *NetworkGameListAddItem(NetworkAddress address)
{
const char *hostname = address.GetHostname();
/* Do not query the 'any' address. */
if (StrEmpty(hostname) ||
strcmp(hostname, "0.0.0.0") == 0 ||
strcmp(hostname, "::") == 0) {
return nullptr;
}
NetworkGameList *item, *prev_item;
prev_item = nullptr;
@ -95,7 +86,6 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address)
} else {
prev_item->next = item;
}
DEBUG(net, 4, "[gamelist] added server to list");
UpdateNetworkGameWindow();

View File

@ -472,9 +472,8 @@ public:
EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
#endif
this->last_joined = NetworkGameListAddItem(ParseConnectionString(_settings_client.network.last_joined, NETWORK_DEFAULT_PORT));
this->last_joined = NetworkAddServer(_settings_client.network.last_joined);
this->server = this->last_joined;
if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
@ -750,7 +749,7 @@ public:
break;
case WID_NG_REFRESH: // Refresh
if (this->server != nullptr) NetworkUDPQueryServer(this->server->address);
if (this->server != nullptr) NetworkTCPQueryServer(this->server->address);
break;
case WID_NG_NEWGRF: // NewGRF Settings
@ -971,7 +970,7 @@ void ShowNetworkGameWindow()
first = false;
/* Add all servers from the config file to our list. */
for (const auto &iter : _network_host_list) {
NetworkAddServer(iter.c_str());
NetworkAddServer(iter);
}
}
@ -1485,7 +1484,7 @@ struct NetworkLobbyWindow : public Window {
/* Clear the information so removed companies don't remain */
for (auto &company : this->company_info) company = {};
NetworkTCPQueryServer(this->server->address);
NetworkTCPQueryServer(this->server->address, true);
break;
}
}
@ -1555,7 +1554,7 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
strecpy(_settings_client.network.last_joined, ngl->address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined));
NetworkTCPQueryServer(ngl->address);
NetworkTCPQueryServer(ngl->address, true);
new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
}

View File

@ -87,10 +87,10 @@ extern uint8 _network_reconnect;
extern CompanyMask _network_company_passworded;
void NetworkTCPQueryServer(NetworkAddress address);
void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info = false);
void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
void NetworkAddServer(const char *b);
struct NetworkGameList *NetworkAddServer(const std::string &connection_string);
void NetworkRebuildHostList();
void UpdateNetworkGameWindow();