summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/network/core/tcp_coordinator.cpp4
-rw-r--r--src/network/core/tcp_coordinator.h29
-rw-r--r--src/network/network_coordinator.cpp66
-rw-r--r--src/network/network_coordinator.h10
-rw-r--r--src/network/network_gui.cpp40
5 files changed, 136 insertions, 13 deletions
diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp
index 1cf5cd676..bbcb59b14 100644
--- a/src/network/core/tcp_coordinator.cpp
+++ b/src/network/core/tcp_coordinator.cpp
@@ -31,6 +31,8 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p)
case PACKET_COORDINATOR_SERVER_REGISTER: return this->Receive_SERVER_REGISTER(p);
case PACKET_COORDINATOR_GC_REGISTER_ACK: return this->Receive_GC_REGISTER_ACK(p);
case PACKET_COORDINATOR_SERVER_UPDATE: return this->Receive_SERVER_UPDATE(p);
+ case PACKET_COORDINATOR_CLIENT_LISTING: return this->Receive_CLIENT_LISTING(p);
+ case PACKET_COORDINATOR_GC_LISTING: return this->Receive_GC_LISTING(p);
default:
Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type);
@@ -78,3 +80,5 @@ bool NetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p) { return this-
bool NetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_REGISTER); }
bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_REGISTER_ACK); }
bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); }
+bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); }
+bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); }
diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h
index a438f07aa..e95916816 100644
--- a/src/network/core/tcp_coordinator.h
+++ b/src/network/core/tcp_coordinator.h
@@ -29,6 +29,8 @@ enum PacketCoordinatorType {
PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration.
PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration.
PACKET_COORDINATOR_SERVER_UPDATE, ///< Server sends an set intervals an update of the server.
+ PACKET_COORDINATOR_CLIENT_LISTING, ///< Client is requesting a listing of all public servers.
+ PACKET_COORDINATOR_GC_LISTING, ///< Game Coordinator returns a listing of all public servers.
PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period).
};
@@ -101,6 +103,33 @@ protected:
*/
virtual bool Receive_SERVER_UPDATE(Packet *p);
+ /**
+ * Client requests a list of all public servers.
+ *
+ * uint8 Game Coordinator protocol version.
+ * uint8 Game-info version used by this client.
+ * string Revision of the client.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_CLIENT_LISTING(Packet *p);
+
+ /**
+ * Game Coordinator replies with a list of all public servers. Multiple
+ * of these packets are received after a request till all servers are
+ * sent over. Last packet will have server count of 0.
+ *
+ * uint16 Amount of public servers in this packet.
+ * For each server:
+ * string Connection string for this server.
+ * Serialized NetworkGameInfo. See game_info.hpp for details.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_GC_LISTING(Packet *p);
+
bool HandlePacket(Packet *p);
public:
/**
diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp
index 3e4079740..b9299d549 100644
--- a/src/network/network_coordinator.cpp
+++ b/src/network/network_coordinator.cpp
@@ -19,6 +19,7 @@
#include "network.h"
#include "network_coordinator.h"
#include "network_gamelist.h"
+#include "network_internal.h"
#include "table/strings.h"
#include "../safeguards.h"
@@ -47,6 +48,7 @@ public:
assert(_network_coordinator_client.sock == INVALID_SOCKET);
_network_coordinator_client.sock = s;
+ _network_coordinator_client.last_activity = std::chrono::steady_clock::now();
_network_coordinator_client.connecting = false;
}
};
@@ -111,6 +113,42 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p)
return true;
}
+bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p)
+{
+ uint8 servers = p->Recv_uint16();
+
+ /* End of list; we can now remove all expired items from the list. */
+ if (servers == 0) {
+ NetworkGameListRemoveExpired();
+ return true;
+ }
+
+ for (; servers > 0; servers--) {
+ std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
+
+ /* Read the NetworkGameInfo from the packet. */
+ NetworkGameInfo ngi = {};
+ DeserializeNetworkGameInfo(p, &ngi);
+
+ /* Now we know the join-key, we can add it to our list. */
+ NetworkGameList *item = NetworkGameListAddItem(connection_string);
+
+ /* Clear any existing GRFConfig chain. */
+ ClearGRFConfigList(&item->info.grfconfig);
+ /* Copy the new NetworkGameInfo info. */
+ item->info = ngi;
+ /* Check for compatability with the client. */
+ CheckGameCompatibility(item->info);
+ /* Mark server as online. */
+ item->online = true;
+ /* Mark the item as up-to-date. */
+ item->version = _network_game_list_version;
+ }
+
+ UpdateNetworkGameWindow();
+ return true;
+}
+
void ClientNetworkCoordinatorSocketHandler::Connect()
{
/* We are either already connected or are trying to connect. */
@@ -119,6 +157,8 @@ void ClientNetworkCoordinatorSocketHandler::Connect()
this->Reopen();
this->connecting = true;
+ this->last_activity = std::chrono::steady_clock::now();
+
new NetworkCoordinatorConnecter(NETWORK_COORDINATOR_SERVER_HOST);
}
@@ -173,6 +213,23 @@ void ClientNetworkCoordinatorSocketHandler::SendServerUpdate()
}
/**
+ * Request a listing of all public servers.
+ */
+void ClientNetworkCoordinatorSocketHandler::GetListing()
+{
+ this->Connect();
+
+ _network_game_list_version++;
+
+ Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_LISTING);
+ p->Send_uint8(NETWORK_COORDINATOR_VERSION);
+ p->Send_uint8(NETWORK_GAME_INFO_VERSION);
+ p->Send_string(_openttd_revision);
+
+ this->SendPacket(p);
+}
+
+/**
* Check whether we received/can send some data from/to the Game Coordinator server and
* when that's the case handle it appropriately.
*/
@@ -226,8 +283,15 @@ void ClientNetworkCoordinatorSocketHandler::SendReceive()
this->SendServerUpdate();
}
+ if (!_network_server && std::chrono::steady_clock::now() > this->last_activity + IDLE_TIMEOUT) {
+ this->CloseConnection();
+ return;
+ }
+
if (this->CanSendReceive()) {
- this->ReceivePackets();
+ if (this->ReceivePackets()) {
+ this->last_activity = std::chrono::steady_clock::now();
+ }
}
this->SendPackets();
diff --git a/src/network/network_coordinator.h b/src/network/network_coordinator.h
index 1dbce063b..7399ce1fc 100644
--- a/src/network/network_coordinator.h
+++ b/src/network/network_coordinator.h
@@ -21,6 +21,10 @@
* - Game Coordinator probes server to check if it can directly connect.
* - Game Coordinator sends GC_REGISTER_ACK with type of connection.
* - Server sends every 30 seconds SERVER_UPDATE.
+ *
+ * For clients (listing):
+ * - Client sends CLIENT_LISTING.
+ * - Game Coordinator returns the full list of public servers via GC_LISTING (multiple packets).
*/
/** Class for handling the client side of the Game Coordinator connection. */
@@ -31,8 +35,13 @@ private:
protected:
bool Receive_GC_ERROR(Packet *p) override;
bool Receive_GC_REGISTER_ACK(Packet *p) override;
+ bool Receive_GC_LISTING(Packet *p) override;
public:
+ /** The idle timeout; when to close the connection because it's idle. */
+ static constexpr std::chrono::seconds IDLE_TIMEOUT = std::chrono::seconds(60);
+
+ std::chrono::steady_clock::time_point last_activity; ///< The last time there was network activity.
bool connecting; ///< Are we connecting to the Game Coordinator?
ClientNetworkCoordinatorSocketHandler() : connecting(false) {}
@@ -44,6 +53,7 @@ public:
void Register();
void SendServerUpdate();
+ void GetListing();
};
extern ClientNetworkCoordinatorSocketHandler _network_coordinator_client;
diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp
index 6f48bf022..24884ed16 100644
--- a/src/network/network_gui.cpp
+++ b/src/network/network_gui.cpp
@@ -18,6 +18,7 @@
#include "network_base.h"
#include "network_content.h"
#include "network_server.h"
+#include "network_coordinator.h"
#include "../gui.h"
#include "network_udp.h"
#include "../window_func.h"
@@ -54,6 +55,8 @@
static void ShowNetworkStartServerWindow();
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
+static const int NETWORK_LIST_REFRESH_DELAY = 30; ///< Time, in seconds, between updates of the network list.
+
static ClientID _admin_client_id = INVALID_CLIENT_ID; ///< For what client a confirmation window is open.
static CompanyID _admin_company_id = INVALID_COMPANY; ///< For what company a confirmation window is open.
@@ -219,14 +222,15 @@ protected:
static GUIGameServerList::SortFunction * const sorter_funcs[];
static GUIGameServerList::FilterFunction * const filter_funcs[];
- NetworkGameList *server; ///< selected server
- NetworkGameList *last_joined; ///< the last joined server
- GUIGameServerList servers; ///< list with game servers.
- ServerListPosition list_pos; ///< position of the selected server
- Scrollbar *vscroll; ///< vertical scrollbar of the list of servers
- QueryString name_editbox; ///< Client name editbox.
- QueryString filter_editbox; ///< Editbox for filter on servers
- GUITimer requery_timer; ///< Timer for network requery
+ NetworkGameList *server; ///< Selected server.
+ NetworkGameList *last_joined; ///< The last joined server.
+ GUIGameServerList servers; ///< List with game servers.
+ ServerListPosition list_pos; ///< Position of the selected server.
+ Scrollbar *vscroll; ///< Vertical scrollbar of the list of servers.
+ QueryString name_editbox; ///< Client name editbox.
+ QueryString filter_editbox; ///< Editbox for filter on servers.
+ GUITimer requery_timer; ///< Timer for network requery.
+ bool searched_internet = false; ///< Did we ever press "Search Internet" button?
int lock_offset; ///< Left offset for lock icon.
int blot_offset; ///< Left offset for green/yellow/red compatibility icon.
@@ -244,8 +248,18 @@ protected:
/* Create temporary array of games to use for listing */
this->servers.clear();
+ bool found_current_server = false;
for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) {
this->servers.push_back(ngl);
+ if (ngl == this->server) {
+ found_current_server = true;
+ }
+ }
+ /* A refresh can cause the current server to be delete; so unselect. */
+ if (!found_current_server) {
+ if (this->server == this->last_joined) this->last_joined = nullptr;
+ this->server = nullptr;
+ this->list_pos = SLP_INVALID;
}
/* Apply the filter condition immediately, if a search string has been provided. */
@@ -479,7 +493,7 @@ public:
this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
this->server = this->last_joined;
- this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
+ this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000);
this->servers.SetListing(this->last_sorting);
this->servers.SetSortFuncs(this->sorter_funcs);
@@ -725,7 +739,8 @@ public:
}
case WID_NG_SEARCH_INTERNET:
- NetworkUDPQueryMasterServer();
+ _network_coordinator_client.GetListing();
+ this->searched_internet = true;
break;
case WID_NG_SEARCH_LAN:
@@ -841,10 +856,11 @@ public:
void OnRealtimeTick(uint delta_ms) override
{
+ if (!this->searched_internet) return;
if (!this->requery_timer.Elapsed(delta_ms)) return;
- this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
+ this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000);
- NetworkGameListRequery();
+ _network_coordinator_client.GetListing();
}
};