summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/network/network_client.cpp80
-rw-r--r--src/network/network_client.h17
2 files changed, 84 insertions, 13 deletions
diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp
index 84fa325cd..9b9b55d97 100644
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -40,7 +40,7 @@
* 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), download_file(NULL)
+ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), download_file(NULL), status(STATUS_INACTIVE)
{
assert(ClientNetworkGameSocketHandler::my_client == NULL);
ClientNetworkGameSocketHandler::my_client = this;
@@ -269,22 +269,22 @@ void HashCurrentCompanyPassword(const char *password)
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyInformationQuery()
{
- Packet *p;
+ my_client->status = STATUS_COMPANY_INFO;
_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, 0);
- p = new Packet(PACKET_CLIENT_COMPANY_INFO);
+ Packet *p = new Packet(PACKET_CLIENT_COMPANY_INFO);
my_client->Send_Packet(p);
return NETWORK_RECV_STATUS_OKAY;
}
NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin()
{
- Packet *p;
+ my_client->status = STATUS_JOIN;
_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, 0);
- p = new Packet(PACKET_CLIENT_JOIN);
+ Packet *p = new Packet(PACKET_CLIENT_JOIN);
p->Send_string(_openttd_revision);
p->Send_string(_settings_client.network.client_name); // Client name
p->Send_uint8 (_network_join_as); // PlayAs
@@ -318,6 +318,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap()
{
+ my_client->status = STATUS_MAP_WAIT;
+
Packet *p = new Packet(PACKET_CLIENT_GETMAP);
/* Send the OpenTTD version to the server, let it validate it too.
* But only do it for stable releases because of those we are sure
@@ -332,6 +334,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap()
NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk()
{
+ my_client->status = STATUS_ACTIVE;
+
Packet *p = new Packet(PACKET_CLIENT_MAP_OK);
my_client->Send_Packet(p);
return NETWORK_RECV_STATUS_OKAY;
@@ -454,6 +458,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_BANNED)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_COMPANY_INFO)
{
+ if (this->status != STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
byte company_info_version = p->Recv_uint8();
if (!this->HasClientQuit() && company_info_version == NETWORK_COMPANY_INFO_VERSION) {
@@ -503,6 +509,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CLIENT_INFO)
p->Recv_string(name, sizeof(name));
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
ci = NetworkFindClientInfoFromClientID(client_id);
@@ -579,6 +586,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHECK_NEWGRFS)
{
+ if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
uint grf_count = p->Recv_uint8();
NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY;
@@ -610,6 +619,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHECK_NEWGRFS)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_NEED_GAME_PASSWORD)
{
+ if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+ this->status = STATUS_AUTH_GAME;
+
const char *password = _network_join_server_password;
if (!StrEmpty(password)) {
return SendGamePassword(password);
@@ -622,6 +634,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_NEED_GAME_PASSWORD)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_NEED_COMPANY_PASSWORD)
{
+ if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+ this->status = STATUS_AUTH_COMPANY;
+
_password_game_seed = p->Recv_uint32();
p->Recv_string(_password_server_id, sizeof(_password_server_id));
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
@@ -638,6 +653,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_NEED_COMPANY_PASSWORD)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_WELCOME)
{
+ if (this->status < STATUS_JOIN || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+ this->status = STATUS_AUTHORIZED;
+
_network_own_client_id = (ClientID)p->Recv_uint32();
/* Initialize the password hash salting variables, even if they were previously. */
@@ -650,6 +668,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_WELCOME)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_WAIT)
{
+ if (this->status != STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+ this->status = STATUS_MAP_WAIT;
+
_network_join_status = NETWORK_JOIN_STATUS_WAITING;
_network_join_waiting = p->Recv_uint8();
SetWindowDirty(WC_NETWORK_STATUS_WINDOW, 0);
@@ -663,6 +684,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_WAIT)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_BEGIN)
{
+ if (this->status < STATUS_AUTHORIZED || this->status >= STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+ this->status = STATUS_MAP;
+
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
if (this->download_file != NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
@@ -693,6 +717,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_BEGIN)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_DATA)
{
+ if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->download_file == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
/* We are still receiving data, put it to the file */
@@ -711,6 +736,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_DATA)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_DONE)
{
+ if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->download_file == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
fclose(this->download_file);
@@ -753,6 +779,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MAP_DONE)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_FRAME)
{
+ if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
_frame_counter_server = p->Recv_uint32();
_frame_counter_max = p->Recv_uint32();
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
@@ -781,6 +809,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_FRAME)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_SYNC)
{
+ if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
_sync_frame = p->Recv_uint32();
_sync_seed_1 = p->Recv_uint32();
#ifdef NETWORK_SEND_DOUBLE_SEED
@@ -792,6 +822,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_SYNC)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_COMMAND)
{
+ if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
CommandPacket cp;
const char *err = this->Recv_Command(p, &cp);
cp.frame = p->Recv_uint32();
@@ -809,6 +841,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_COMMAND)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT)
{
+ if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH];
const NetworkClientInfo *ci = NULL, *ci_to;
@@ -859,6 +893,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR_QUIT)
{
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
ClientID client_id = (ClientID)p->Recv_uint32();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
@@ -874,11 +910,11 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR_QUIT)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_QUIT)
{
- NetworkClientInfo *ci;
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
ClientID client_id = (ClientID)p->Recv_uint32();
- ci = NetworkFindClientInfoFromClientID(client_id);
+ NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
if (ci != NULL) {
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
delete ci;
@@ -894,6 +930,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_QUIT)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_JOIN)
{
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
ClientID client_id = (ClientID)p->Recv_uint32();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
@@ -908,24 +946,34 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_JOIN)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_SHUTDOWN)
{
- _switch_mode_errorstr = STR_NETWORK_MESSAGE_SERVER_SHUTDOWN;
+ /* Only when we're trying to join we really
+ * care about the server shutting down. */
+ if (this->status >= STATUS_JOIN) {
+ _switch_mode_errorstr = STR_NETWORK_MESSAGE_SERVER_SHUTDOWN;
+ }
return NETWORK_RECV_STATUS_SERVER_ERROR;
}
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_NEWGAME)
{
- /* To trottle the reconnects a bit, every clients waits its
- * Client ID modulo 16. This way reconnects should be spread
- * out a bit. */
- _network_reconnect = _network_own_client_id % 16;
- _switch_mode_errorstr = STR_NETWORK_MESSAGE_SERVER_REBOOT;
+ /* Only when we're trying to join we really
+ * care about the server shutting down. */
+ if (this->status >= STATUS_JOIN) {
+ /* To trottle the reconnects a bit, every clients waits its
+ * Client ID modulo 16. This way reconnects should be spread
+ * out a bit. */
+ _network_reconnect = _network_own_client_id % 16;
+ _switch_mode_errorstr = STR_NETWORK_MESSAGE_SERVER_REBOOT;
+ }
return NETWORK_RECV_STATUS_SERVER_ERROR;
}
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_RCON)
{
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
char rcon_out[NETWORK_RCONCOMMAND_LENGTH];
ConsoleColour colour_code = (ConsoleColour)p->Recv_uint16();
@@ -938,6 +986,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_RCON)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MOVE)
{
+ if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
/* Nothing more in this packet... */
ClientID client_id = (ClientID)p->Recv_uint32();
CompanyID company_id = (CompanyID)p->Recv_uint8();
@@ -964,6 +1014,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MOVE)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CONFIG_UPDATE)
{
+ if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
_network_server_max_companies = p->Recv_uint8();
_network_server_max_spectators = p->Recv_uint8();
@@ -972,6 +1024,8 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CONFIG_UPDATE)
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_COMPANY_UPDATE)
{
+ if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
_network_company_passworded = p->Recv_uint16();
SetWindowClassesDirty(WC_COMPANY);
diff --git a/src/network/network_client.h b/src/network/network_client.h
index 90e37d278..f47fe0b65 100644
--- a/src/network/network_client.h
+++ b/src/network/network_client.h
@@ -21,6 +21,23 @@ class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public Netw
private:
FILE *download_file; ///< Handle used for downloading the savegame.
+ /** Status of the connection with the server. */
+ enum ServerStatus {
+ STATUS_INACTIVE, ///< The client is not connected nor active.
+ 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.
+ STATUS_AUTH_GAME, ///< Last action was requesting game (server) password.
+ STATUS_AUTH_COMPANY, ///< Last action was requestion company password.
+ STATUS_AUTHORIZED, ///< The client is authorized at the server.
+ STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
+ STATUS_MAP, ///< The client is downloading the map.
+ STATUS_ACTIVE, ///< The client is active within in the game.
+ STATUS_END ///< Must ALWAYS be on the end of this list!! (period)
+ };
+
+ ServerStatus status; ///< Status of the connection with the server.
+
protected:
friend void NetworkExecuteLocalCommandQueue();
friend void NetworkClose(bool close_admins);