(svn r20553) -Feature: allow rate limiting of incoming commands

This commit is contained in:
rubidium 2010-08-19 08:59:36 +00:00
parent cfc0df152b
commit a4c6d07edc
9 changed files with 31 additions and 6 deletions

View File

@ -1757,6 +1757,7 @@ STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The serv
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
@ -1774,6 +1775,7 @@ STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company i
STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server
STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat
STR_NETWORK_ERROR_CLIENT_SERVER_FULL :server full
STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :was sending too many commands
############ End of leave-in-this-order
# Network related errors

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -110,6 +110,7 @@ enum NetworkErrorCode {
NETWORK_ERROR_KICKED,
NETWORK_ERROR_CHEATER,
NETWORK_ERROR_FULL,
NETWORK_ERROR_TOO_MANY_COMMANDS,
};
#endif /* ENABLE_NETWORK */

View File

@ -128,6 +128,8 @@ struct NetworkSettings {
#ifdef ENABLE_NETWORK
uint16 sync_freq; ///< how often do we check whether we are still in-sync
uint8 frame_freq; ///< how often do we send commands to the clients
uint16 commands_per_frame; ///< how many commands may be sent each frame_freq frames?
uint16 max_commands_in_queue; ///< how many commands may there be in the incoming queue before dropping the connection?
uint16 max_join_time; ///< maximum amount of time, in game ticks, a client may take to join
bool pause_on_join; ///< pause the game when people join
uint16 server_port; ///< port the server listens on

View File

@ -622,6 +622,8 @@ const SettingDesc _settings[] = {
SDTC_VAR(network.sync_freq, SLE_UINT16,C|S,NO, 100, 0, 100, 0, STR_NULL, NULL),
SDTC_VAR(network.frame_freq, SLE_UINT8,C|S,NO, 0, 0, 100, 0, STR_NULL, NULL),
SDTC_VAR(network.commands_per_frame, SLE_UINT16, S, NO, 4, 1, 65535, 0, STR_NULL, NULL),
SDTC_VAR(network.max_commands_in_queue,SLE_UINT16, S, NO, 32, 1, 65535, 0, STR_NULL, NULL),
SDTC_VAR(network.max_join_time, SLE_UINT16, S, NO, 500, 0, 32000, 0, STR_NULL, NULL),
SDTC_BOOL(network.pause_on_join, S, NO, true, STR_NULL, NULL),
SDTC_VAR(network.server_port, SLE_UINT16, S, NO,NETWORK_DEFAULT_PORT,0,65535,0,STR_NULL, NULL),