From 31c8ab0ed895b8a67a0d6720f92b7a0e77956454 Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 30 Nov 2010 14:18:20 +0000 Subject: [PATCH] (svn r21361) -Change: make sure the client is listening, or rather receiving, our frames --- src/network/core/tcp_game.h | 2 ++ src/network/network_client.cpp | 6 +++++- src/network/network_client.h | 1 + src/network/network_server.cpp | 31 +++++++++++++++++++++++++++++++ src/network/network_server.h | 2 ++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index be737554ed..24adf6acd7 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -304,6 +304,7 @@ protected: * uint32 Frame counter max (how far may the client walk before the server?) * uint32 General seed 1 (dependant on compile settings, not default). * uint32 General seed 2 (dependant on compile settings, not default). + * uint8 Random token to validate the client is actually listening (only occasionally present). */ DECLARE_GAME_RECEIVE_COMMAND(PACKET_SERVER_FRAME); @@ -318,6 +319,7 @@ protected: /** * Tell the server we are done with this frame: * uint32 Current frame counter of the client. + * uint8 The random token that the server sent in the PACKET_SERVER_FRAME packet. */ DECLARE_GAME_RECEIVE_COMMAND(PACKET_CLIENT_ACK); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 07b1cfb985..7d1e7f6690 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -349,6 +349,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck() Packet *p = new Packet(PACKET_CLIENT_ACK); p->Send_uint32(_frame_counter); + p->Send_uint8 (my_client->token); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -798,7 +799,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_FRAME) #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME /* Test if the server supports this option * and if we are at the frame the server is */ - if (p->pos < p->size) { + if (p->pos + 1 < p->size) { _sync_frame = _frame_counter_server; _sync_seed_1 = p->Recv_uint32(); #ifdef NETWORK_SEND_DOUBLE_SEED @@ -806,6 +807,9 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_FRAME) #endif } #endif + /* Receive the token. */ + if (p->pos != p->size) this->token = p->Recv_uint8(); + DEBUG(net, 5, "Received FRAME %d", _frame_counter_server); /* Let the server know that we received this frame correctly diff --git a/src/network/network_client.h b/src/network/network_client.h index bfe4c7613d..cccec668de 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -21,6 +21,7 @@ class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public Netw private: FILE *download_file; ///< Handle used for downloading the savegame. char *download_filename; ///< File name of the downloading savegame, so we open the right one. + 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 { diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 442df0b698..aa0cd7944b 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -33,6 +33,7 @@ #include "../roadveh.h" #include "../order_backup.h" #include "../core/pool_func.hpp" +#include "../core/random_func.hpp" #include "../rev.h" #include "table/strings.h" @@ -483,6 +484,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame() p->Send_uint32(_sync_seed_2); #endif #endif + + /* If token equals 0, we need to make a new token and send that. */ + if (this->last_token == 0) { + this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1; + p->Send_uint8(this->last_token); + } + this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -982,11 +990,28 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_ACK) /* Now he is! Unpause the game */ this->status = STATUS_ACTIVE; + this->last_token_frame = _frame_counter; /* Execute script for, e.g. MOTD */ IConsoleCmdExec("exec scripts/on_server_connect.scr 0"); } + /* Get, and validate the token. */ + uint8 token = p->Recv_uint8(); + if (token == this->last_token) { + /* We differentiate between last_token_frame and last_frame so the lag + * test uses the actual lag of the client instead of the lag for getting + * the token back and forth; after all, the token is only sent every + * time we receive a PACKET_CLIENT_ACK, after which we will send a new + * token to the client. If the lag would be one day, then we would not + * be sending the new token soon enough for the new daily scheduled + * PACKET_CLIENT_ACK. This would then register the lag of the client as + * two days, even when it's only a single day. */ + this->last_token_frame = _frame_counter; + /* Request a new token. */ + this->last_token = 0; + } + /* The client received the frame, make note of it */ this->last_frame = frame; /* With those 2 values we can calculate the lag realtime */ @@ -1545,6 +1570,12 @@ void NetworkServer_Tick(bool send_frame) } else { cs->lag_test = 0; } + if (cs->last_frame_server - cs->last_token_frame >= 5 * DAY_TICKS) { + /* This is a bad client! It didn't send the right token back. */ + IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id); + cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR); + continue; + } } else if (cs->status == NetworkClientSocket::STATUS_PRE_ACTIVE) { uint lag = NetworkCalculateLag(cs); if (lag > _settings_client.network.max_join_time) { diff --git a/src/network/network_server.h b/src/network/network_server.h index 7c5b175bf7..0185d69bd2 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -66,6 +66,8 @@ public: }; byte lag_test; ///< Byte used for lag-testing the client + byte last_token; ///< The last random token we did send to verify the client is listening + uint32 last_token_frame; ///< The last frame we received the right token ClientStatus status; ///< Status of this client CommandQueue outgoing_queue; ///< The command-queue awaiting delivery