From a4c6d07edc4937087e3f2d0b2bff52cc3980b9e2 Mon Sep 17 00:00:00 2001 From: rubidium Date: Thu, 19 Aug 2010 08:59:36 +0000 Subject: (svn r20553) -Feature: allow rate limiting of incoming commands --- src/network/core/tcp_game.h | 3 +++ src/network/network.cpp | 8 ++++---- src/network/network_client.cpp | 3 +++ src/network/network_command.cpp | 12 ++++++++++-- src/network/network_server.cpp | 4 ++++ src/network/network_type.h | 1 + 6 files changed, 25 insertions(+), 6 deletions(-) (limited to 'src/network') diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index a7d3bb462..acbd47ed8 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -78,6 +78,7 @@ struct CommandPacket; class CommandQueue { CommandPacket *first; ///< The first packet in the queue. CommandPacket *last; ///< The last packet in the queue; only valid when first != NULL. + uint count; ///< The number of items in the queue. public: /** Initialise the command queue. */ @@ -88,6 +89,8 @@ public: CommandPacket *Pop(); CommandPacket *Peek(); void Free(); + /** Get the number of items in the queue. */ + uint Count() const { return this->count; } }; /** Status of a client */ diff --git a/src/network/network.cpp b/src/network/network.cpp index cf74c621b..00863f8ad 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -344,7 +344,8 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err) STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH, STR_NETWORK_ERROR_CLIENT_KICKED, STR_NETWORK_ERROR_CLIENT_CHEATER, - STR_NETWORK_ERROR_CLIENT_SERVER_FULL + STR_NETWORK_ERROR_CLIENT_SERVER_FULL, + STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS }; if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL; @@ -1181,14 +1182,13 @@ void NetworkGameLoop() f = NULL; } #endif /* DEBUG_DUMP_COMMANDS */ - NetworkDistributeCommands(); - if (_frame_counter >= _frame_counter_max) { /* Only check for active clients just before we're going to send out * the commands so we don't send multiple pause/unpause commands when - * the frame_freq is more than 1 tick. */ + * the frame_freq is more than 1 tick. Same with distributing commands. */ CheckPauseOnJoin(); CheckMinActiveClients(); + NetworkDistributeCommands(); } bool send_frame = false; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index ea478276b..b6ffcbb22 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -515,6 +515,9 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) case NETWORK_ERROR_CHEATER: _switch_mode_errorstr = STR_NETWORK_ERROR_CHEATER; break; + case NETWORK_ERROR_TOO_MANY_COMMANDS: + _switch_mode_errorstr = STR_NETWORK_ERROR_TOO_MANY_COMMANDS; + break; default: _switch_mode_errorstr = STR_NETWORK_ERROR_LOSTCONNECTION; } diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 1bec93c7a..1b1712203 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -17,6 +17,7 @@ #include "network.h" #include "../command_func.h" #include "../company_func.h" +#include "../settings_type.h" /** Table with all the callbacks we'll use for conversion*/ static CommandCallback * const _callback_table[] = { @@ -68,6 +69,7 @@ void CommandQueue::Append(CommandPacket *p) this->last->next = add; } this->last = add; + this->count++; } /** @@ -77,7 +79,10 @@ void CommandQueue::Append(CommandPacket *p) CommandPacket *CommandQueue::Pop() { CommandPacket *ret = this->first; - if (ret != NULL) this->first = this->first->next; + if (ret != NULL) { + this->first = this->first->next; + this->count--; + } return ret; } @@ -97,6 +102,7 @@ void CommandQueue::Free() while ((cp = this->Pop()) != NULL) { free(cp); } + assert(this->count == 0); } /** Local queue of packets waiting for handling. */ @@ -241,8 +247,10 @@ static void DistributeCommandPacket(CommandPacket cp, const NetworkClientSocket */ static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner) { + int to_go = _settings_client.network.commands_per_frame; + CommandPacket *cp; - while ((cp = queue->Pop()) != NULL) { + while (--to_go >= 0 && (cp = queue->Pop()) != NULL) { DistributeCommandPacket(*cp, owner); free(cp); } diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index dc7d9d0f6..b8ea9fa62 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -897,6 +897,10 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) return SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); } + if (cs->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) { + return SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_TOO_MANY_COMMANDS); + } + CommandPacket cp; const char *err = cs->Recv_Command(p, &cp); diff --git a/src/network/network_type.h b/src/network/network_type.h index a86ad9948..5b83620e6 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -110,6 +110,7 @@ enum NetworkErrorCode { NETWORK_ERROR_KICKED, NETWORK_ERROR_CHEATER, NETWORK_ERROR_FULL, + NETWORK_ERROR_TOO_MANY_COMMANDS, }; #endif /* ENABLE_NETWORK */ -- cgit v1.2.3-70-g09d2