(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)
This commit is contained in:
rubidium 2007-03-19 19:34:44 +00:00
parent 759d155b08
commit 1e7cca8f8b
5 changed files with 55 additions and 31 deletions

View File

@ -529,6 +529,7 @@ DEF_CONSOLE_CMD(ConStatus)
{
static const char* const stat_str[] = {
"inactive",
"authorizing",
"authorized",
"waiting",
"loading map",

View File

@ -168,7 +168,7 @@ void ResetCurrencies(void)
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 */

View File

@ -362,6 +362,40 @@ void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
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 @@ static void PlayersCheckBankrupt(Player *p)
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 @@ static void DoAcquireCompany(Player *p)
// original code does this a little bit differently
pi = p->index;
ChangeNetworkOwner(pi, _current_player);
ChangeOwnershipOfPlayerItems(pi, _current_player);
if (p->bankrupt_value == 0) {

View File

@ -49,6 +49,7 @@ typedef struct CommandPacket {
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,

View File

@ -215,7 +215,14 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *c
// 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 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD)
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 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD)
// 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 @@ void NetworkServer_Tick(bool send_frame)
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) {