# HG changeset patch # User rubidium # Date 1174332884 0 # Node ID 6d16b7e4f85d1192e99e62bf34aefd40a0c589b5 # Parent 03285c9589f97c81077246e27f4a16d71a4c7295 (svn r9344) [0.5] -Backport from trunk (r9027, r9038, r9061, r9071): - Fix: desync caused by buffer overflow (r9027) - Feature: kick inactive initial network connections after some time (r9038, r9061) - Fix: take over companies properly in multiplayer games (r9071) diff -r 03285c9589f9 -r 6d16b7e4f85d console_cmds.c --- a/console_cmds.c Mon Mar 19 19:22:26 2007 +0000 +++ b/console_cmds.c Mon Mar 19 19:34:44 2007 +0000 @@ -529,6 +529,7 @@ { static const char* const stat_str[] = { "inactive", + "authorizing", "authorized", "waiting", "loading map", diff -r 03285c9589f9 -r 6d16b7e4f85d currency.c --- a/currency.c Mon Mar 19 19:22:26 2007 +0000 +++ b/currency.c Mon Mar 19 19:34:44 2007 +0000 @@ -168,7 +168,7 @@ StringID* BuildCurrencyDropdown(void) { /* Allow room for all currencies, plus a terminator entry */ - static StringID names[CUSTOM_CURRENCY_ID]; + static StringID names[NUM_CURRENCY + 1]; uint i; /* Add each name */ diff -r 03285c9589f9 -r 6d16b7e4f85d economy.c --- a/economy.c Mon Mar 19 19:22:26 2007 +0000 +++ b/economy.c Mon Mar 19 19:34:44 2007 +0000 @@ -362,6 +362,40 @@ MarkWholeScreenDirty(); } +static void ChangeNetworkOwner(PlayerID current_player, PlayerID new_player) +{ +#ifdef ENABLE_NETWORK + if (!_networking) return; + + if (current_player == _local_player) { + _network_playas = new_player; + SetLocalPlayer(new_player); + } + + if (!_network_server) return; + + /* The server has to handle all administrative issues, for example + * updating and notifying all clients of what has happened */ + NetworkClientState *cs; + NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + + /* The server has just changed from player */ + if (current_player == ci->client_playas) { + ci->client_playas = new_player; + NetworkUpdateClientInfo(NETWORK_SERVER_INDEX); + } + + /* Find all clients that were in control of this company, and mark them as new_player */ + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); + if (current_player == ci->client_playas) { + ci->client_playas = new_player; + NetworkUpdateClientInfo(ci->client_index); + } + } +#endif /* ENABLE_NETWORK */ +} + static void PlayersCheckBankrupt(Player *p) { PlayerID owner; @@ -419,35 +453,9 @@ p->bankrupt_asked = 0xFF; p->bankrupt_timeout = 0x456; break; - } else if (owner == _local_player) { - _network_playas = PLAYER_SPECTATOR; - SetLocalPlayer(PLAYER_SPECTATOR); } -#ifdef ENABLE_NETWORK - /* The server has to handle all administrative issues, for example - * updating and notifying all clients of what has happened */ - if (_network_server) { - const NetworkClientState *cs; - NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - - /* The server has just gone belly-up, mark it as spectator */ - if (owner == ci->client_playas) { - ci->client_playas = PLAYER_SPECTATOR; - NetworkUpdateClientInfo(NETWORK_SERVER_INDEX); - } - - /* Find all clients that were in control of this company, - * and mark them as spectator; broadcast this message to everyone */ - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (ci->client_playas == owner) { - ci->client_playas = PLAYER_SPECTATOR; - NetworkUpdateClientInfo(ci->client_index); - } - } - } -#endif /* ENABLE_NETWORK */ + ChangeNetworkOwner(owner, PLAYER_SPECTATOR); } /* Remove the player */ @@ -1572,6 +1580,7 @@ // original code does this a little bit differently pi = p->index; + ChangeNetworkOwner(pi, _current_player); ChangeOwnershipOfPlayerItems(pi, _current_player); if (p->bankrupt_value == 0) { diff -r 03285c9589f9 -r 6d16b7e4f85d network_data.h --- a/network_data.h Mon Mar 19 19:22:26 2007 +0000 +++ b/network_data.h Mon Mar 19 19:34:44 2007 +0000 @@ -49,6 +49,7 @@ typedef enum { STATUS_INACTIVE, + STATUS_AUTHORIZING, // This means that the client is authorizing STATUS_AUTH, // This means that the client is authorized STATUS_MAP_WAIT, // This means that the client is put on hold because someone else is getting the map STATUS_MAP, diff -r 03285c9589f9 -r 6d16b7e4f85d network_server.c --- a/network_server.c Mon Mar 19 19:22:26 2007 +0000 +++ b/network_server.c Mon Mar 19 19:34:44 2007 +0000 @@ -215,7 +215,14 @@ // uint8: Type of password // - Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD); + Packet *p; + + /* Invalid packet when status is AUTH or higher */ + if (cs->status >= STATUS_AUTH) return; + + cs->status = STATUS_AUTHORIZING; + + p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD); NetworkSend_uint8(p, type); NetworkSend_Packet(p, cs); } @@ -694,7 +701,7 @@ type = NetworkRecv_uint8(cs, p); NetworkRecv_string(cs, p, password, sizeof(password)); - if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) { + if (cs->status == STATUS_AUTHORIZING && type == NETWORK_GAME_PASSWORD) { // Check game-password if (strcmp(password, _network_game_info.server_password) != 0) { // Password is invalid @@ -712,7 +719,7 @@ // Valid password, allow user SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); return; - } else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) { + } else if (cs->status == STATUS_AUTHORIZING && type == NETWORK_COMPANY_PASSWORD) { ci = DEREF_CLIENT_INFO(cs); if (strcmp(password, _network_player_info[ci->client_playas].password) != 0) { @@ -1534,6 +1541,12 @@ IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time); NetworkCloseClient(cs); } + } else if (cs->status == STATUS_INACTIVE) { + int lag = NetworkCalculateLag(cs); + if (lag > 4 * DAY_TICKS) { + IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->index, 4 * DAY_TICKS); + NetworkCloseClient(cs); + } } if (cs->status >= STATUS_PRE_ACTIVE) {