diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 899eba771b..0f6eb8f5d6 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -39,7 +39,7 @@ public: bool SendPackets(bool closing_down = false); bool IsPacketQueueEmpty(); - Packet *ReceivePacket(); + virtual Packet *ReceivePacket(); bool CanSendReceive(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index aa0cd7944b..5437cd0066 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -62,6 +62,7 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo { this->status = STATUS_INACTIVE; this->client_id = _network_client_id++; + this->receive_limit = _settings_client.network.bytes_per_frame_burst; NetworkClientInfo *ci = new NetworkClientInfo(this->client_id); this->SetInfo(ci); ci->client_playas = COMPANY_INACTIVE_CLIENT; @@ -77,6 +78,19 @@ ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler() OrderBackup::ResetUser(this->client_id); } +Packet *ServerNetworkGameSocketHandler::ReceivePacket() +{ + /* Only allow receiving when we have some buffer free; this value + * can go negative, but eventually it will become positive again. */ + if (this->receive_limit <= 0) return NULL; + + /* We can receive a packet, so try that and if needed account for + * the amount of received data. */ + Packet *p = this->NetworkTCPSocketHandler::ReceivePacket(); + if (p != NULL) this->receive_limit -= p->size; + return p; +} + NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status) { assert(status != NETWORK_RECV_STATUS_OKAY); @@ -1540,6 +1554,11 @@ void NetworkServer_Tick(bool send_frame) /* Now we are done with the frame, inform the clients that they can * do their frame! */ FOR_ALL_CLIENT_SOCKETS(cs) { + /* We allow a number of bytes per frame, but only to the burst amount + * to be available for packet receiving at any particular time. */ + cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame, + _settings_client.network.bytes_per_frame_burst); + /* Check if the speed of the client is what we can expect from a client */ if (cs->status == NetworkClientSocket::STATUS_ACTIVE) { /* 1 lag-point per day */ diff --git a/src/network/network_server.h b/src/network/network_server.h index 0185d69bd2..89d94a3cc5 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -70,10 +70,12 @@ public: 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 + int receive_limit; ///< Amount of bytes that we can receive at this moment ServerNetworkGameSocketHandler(SOCKET s); ~ServerNetworkGameSocketHandler(); + virtual Packet *ReceivePacket(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status); void GetClientName(char *client_name, size_t size) const; diff --git a/src/settings_type.h b/src/settings_type.h index dc66e86abd..3550c2ad92 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -141,6 +141,8 @@ struct NetworkSettings { 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 bytes_per_frame; ///< how many bytes may, over a long period, be received per frame? + uint16 bytes_per_frame_burst; ///< how many bytes may, over a short period, be received? 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 diff --git a/src/table/settings.h b/src/table/settings.h index bc37d88ab8..757f4cdf5a 100644 --- a/src/table/settings.h +++ b/src/table/settings.h @@ -633,6 +633,8 @@ const SettingDesc _settings[] = { 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.bytes_per_frame, SLE_UINT16, S, NO, 8, 1, 65535, 0, STR_NULL, NULL), + SDTC_VAR(network.bytes_per_frame_burst,SLE_UINT16, S, NO, 256, 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),