Merge branch 'jgrpp' into jgrpp-nrt
# Conflicts: # .ottdrev-vc # README.md # jgrpp-changelog.md # src/ship_cmd.cpp
This commit is contained in:
@@ -41,6 +41,8 @@ NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(nullptr), cl
|
||||
*/
|
||||
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||
{
|
||||
if (this->ignore_close) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||
|
||||
/* Clients drop back to the main menu */
|
||||
if (!_network_server && _networking) {
|
||||
extern void ClientNetworkEmergencySave(); // from network_client.cpp
|
||||
@@ -79,6 +81,8 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
||||
case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p);
|
||||
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
||||
case PACKET_CLIENT_SETTINGS_PASSWORD: return this->Receive_CLIENT_SETTINGS_PASSWORD(p);
|
||||
case PACKET_SERVER_SETTINGS_ACCESS: return this->Receive_SERVER_SETTINGS_ACCESS(p);
|
||||
case PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p);
|
||||
case PACKET_CLIENT_GETMAP: return this->Receive_CLIENT_GETMAP(p);
|
||||
case PACKET_SERVER_WAIT: return this->Receive_SERVER_WAIT(p);
|
||||
@@ -100,6 +104,7 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
||||
case PACKET_CLIENT_QUIT: return this->Receive_CLIENT_QUIT(p);
|
||||
case PACKET_CLIENT_ERROR: return this->Receive_CLIENT_ERROR(p);
|
||||
case PACKET_CLIENT_DESYNC_LOG: return this->Receive_CLIENT_DESYNC_LOG(p);
|
||||
case PACKET_SERVER_DESYNC_LOG: return this->Receive_SERVER_DESYNC_LOG(p);
|
||||
case PACKET_SERVER_QUIT: return this->Receive_SERVER_QUIT(p);
|
||||
case PACKET_SERVER_ERROR_QUIT: return this->Receive_SERVER_ERROR_QUIT(p);
|
||||
case PACKET_SERVER_SHUTDOWN: return this->Receive_SERVER_SHUTDOWN(p);
|
||||
@@ -166,6 +171,8 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Pa
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SETTINGS_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SETTINGS_ACCESS); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
||||
@@ -187,6 +194,7 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p) {
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_LOG); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
||||
|
@@ -63,6 +63,8 @@ enum PacketGameType {
|
||||
PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password.
|
||||
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
||||
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
||||
PACKET_CLIENT_SETTINGS_PASSWORD, ///< Client sends the (hashed) settings password.
|
||||
PACKET_SERVER_SETTINGS_ACCESS, ///< Server sends the settings access state.
|
||||
|
||||
/* The server welcomes the authenticated client and sends information of other clients. */
|
||||
PACKET_SERVER_WELCOME, ///< Server welcomes you and gives you your #ClientID.
|
||||
@@ -122,6 +124,7 @@ enum PacketGameType {
|
||||
PACKET_CLIENT_ERROR, ///< A client reports an error to the server.
|
||||
PACKET_SERVER_ERROR_QUIT, ///< A server tells that a client has hit an error and did quit.
|
||||
PACKET_CLIENT_DESYNC_LOG, ///< A client reports a desync log
|
||||
PACKET_SERVER_DESYNC_LOG, ///< A server reports a desync log
|
||||
|
||||
PACKET_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||
};
|
||||
@@ -158,6 +161,7 @@ private:
|
||||
NetworkClientInfo *info; ///< Client info related to this socket
|
||||
|
||||
protected:
|
||||
bool ignore_close = false;
|
||||
NetworkRecvStatus ReceiveInvalidPacket(PacketGameType type);
|
||||
|
||||
/**
|
||||
@@ -262,6 +266,21 @@ protected:
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p);
|
||||
|
||||
/**
|
||||
* Send a password to the server to authorize
|
||||
* uint8 Password type (see NetworkPasswordType).
|
||||
* string The password.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet *p);
|
||||
|
||||
/**
|
||||
* Indication to the client that the setting access state has changed
|
||||
* bool setting access state
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet *p);
|
||||
|
||||
/**
|
||||
* The client is joined and ready to receive his map:
|
||||
* uint32 Own client ID.
|
||||
@@ -428,6 +447,7 @@ protected:
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_DESYNC_LOG(Packet *p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_DESYNC_LOG(Packet *p);
|
||||
|
||||
/**
|
||||
* Notification that a client left the game:
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "../core/pool_func.hpp"
|
||||
#include "../gfx_func.h"
|
||||
#include "../error.h"
|
||||
#include "../core/checksum_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -56,6 +57,7 @@ bool _network_server; ///< network-server is active
|
||||
bool _network_available; ///< is network mode available?
|
||||
bool _network_dedicated; ///< are we a dedicated server?
|
||||
bool _is_network_server; ///< Does this client wants to be a network-server?
|
||||
bool _network_settings_access; ///< Can this client change server settings?
|
||||
NetworkServerGameInfo _network_game_info; ///< Information about our game.
|
||||
NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
|
||||
ClientID _network_own_client_id; ///< Our client identifier.
|
||||
@@ -74,6 +76,7 @@ uint32 _sync_seed_1; ///< Seed to compare during sync checks.
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
uint32 _sync_seed_2; ///< Second part of the seed.
|
||||
#endif
|
||||
uint64 _sync_state_checksum; ///< State checksum to compare during sync checks.
|
||||
uint32 _sync_frame; ///< The frame to perform the sync check.
|
||||
bool _network_first_time; ///< Whether we have finished joining or not.
|
||||
bool _network_udp_server; ///< Is the UDP server started?
|
||||
@@ -893,7 +896,7 @@ void NetworkGameLoop()
|
||||
/* We don't want to log multiple times if paused. */
|
||||
static Date last_log;
|
||||
if (last_log != _date) {
|
||||
DEBUG(desync, 1, "sync: date{%08x; %02x; %02x}; %08x; %08x", _date, _date_fract, _tick_skip_counter, _random.state[0], _random.state[1]);
|
||||
DEBUG(desync, 2, "sync: date{%08x; %02x; %02x}; %08x; %08x", _date, _date_fract, _tick_skip_counter, _random.state[0], _random.state[1]);
|
||||
last_log = _date;
|
||||
}
|
||||
}
|
||||
@@ -1028,6 +1031,7 @@ void NetworkGameLoop()
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
_sync_seed_2 = _random.state[1];
|
||||
#endif
|
||||
_sync_state_checksum = _state_checksum.state;
|
||||
|
||||
NetworkServer_Tick(send_frame);
|
||||
} else {
|
||||
|
@@ -22,5 +22,6 @@ extern bool _network_server; ///< network-server is active
|
||||
extern bool _network_available; ///< is network mode available?
|
||||
extern bool _network_dedicated; ///< are we a dedicated server?
|
||||
extern bool _is_network_server; ///< Does this client wants to be a network-server?
|
||||
extern bool _network_settings_access; ///< Can this client change server settings?
|
||||
|
||||
#endif /* NETWORK_H */
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include "../core/backup_type.hpp"
|
||||
#include "../thread.h"
|
||||
#include "../crashlog.h"
|
||||
#include "../core/checksum_func.hpp"
|
||||
#include "../fileio_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -134,6 +136,7 @@ void ClientNetworkEmergencySave()
|
||||
{
|
||||
if (!_settings_client.gui.autosave_on_network_disconnect) return;
|
||||
if (!_networking) return;
|
||||
if (!ClientNetworkGameSocketHandler::EmergencySavePossible()) return;
|
||||
|
||||
const char *filename = "netsave.sav";
|
||||
DEBUG(net, 0, "Client: Performing emergency save (%s)", filename);
|
||||
@@ -158,8 +161,18 @@ ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler()
|
||||
{
|
||||
assert(ClientNetworkGameSocketHandler::my_client == this);
|
||||
ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||
_network_settings_access = false;
|
||||
|
||||
delete this->savegame;
|
||||
|
||||
if (this->desync_log_file) {
|
||||
if (!this->server_desync_log.empty()) {
|
||||
fwrite("\n", 1, 1, this->desync_log_file);
|
||||
fwrite(this->server_desync_log.data(), 1, this->server_desync_log.size(), this->desync_log_file);
|
||||
}
|
||||
FioFCloseFile(this->desync_log_file);
|
||||
this->desync_log_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
|
||||
@@ -173,6 +186,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
* that code any more complex or more aware of the validity of the socket.
|
||||
*/
|
||||
if (this->sock == INVALID_SOCKET) return status;
|
||||
if (this->status == STATUS_CLOSING) return status;
|
||||
|
||||
DEBUG(net, 1, "Shutting down client connection %d", this->client_id);
|
||||
|
||||
@@ -190,6 +204,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
|
||||
DEBUG(net, 1, "Shutdown client connection %d", this->client_id);
|
||||
|
||||
if (status == NETWORK_RECV_STATUS_DESYNC) {
|
||||
this->status = STATUS_CLOSING;
|
||||
this->ignore_close = true;
|
||||
this->ReceivePackets();
|
||||
}
|
||||
|
||||
delete this->GetInfo();
|
||||
delete this;
|
||||
|
||||
@@ -282,16 +302,26 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
if (_sync_frame != 0) {
|
||||
if (_sync_frame == _frame_counter) {
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
|
||||
if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1] || _sync_state_checksum != _state_checksum.state) {
|
||||
#else
|
||||
if (_sync_seed_1 != _random.state[0]) {
|
||||
if (_sync_seed_1 != _random.state[0] || _sync_state_checksum != _state_checksum.state) {
|
||||
#endif
|
||||
DesyncExtraInfo info;
|
||||
if (_sync_seed_1 != _random.state[0]) info.flags |= DesyncExtraInfo::DEIF_RAND1;
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
if (_sync_seed_2 != _random.state[1]) info.flags |= DesyncExtraInfo::DEIF_RAND2;
|
||||
info.flags |= DesyncExtraInfo::DEIF_DBL_RAND;
|
||||
#endif
|
||||
if (_sync_state_checksum != _state_checksum.state) info.flags |= DesyncExtraInfo::DEIF_STATE;
|
||||
|
||||
NetworkError(STR_NETWORK_ERROR_DESYNC);
|
||||
DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x}", _date, _date_fract, _tick_skip_counter);
|
||||
DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x} {%x, " OTTD_PRINTFHEX64 "} != {%x, " OTTD_PRINTFHEX64 "}"
|
||||
, _date, _date_fract, _tick_skip_counter, _sync_seed_1, _sync_state_checksum, _random.state[0], _state_checksum.state);
|
||||
DEBUG(net, 0, "Sync error detected!");
|
||||
|
||||
std::string desync_log;
|
||||
CrashLog::DesyncCrashLog(nullptr, &desync_log);
|
||||
info.log_file = &(my_client->desync_log_file);
|
||||
CrashLog::DesyncCrashLog(nullptr, &desync_log, info);
|
||||
my_client->SendDesyncLog(desync_log);
|
||||
my_client->ClientError(NETWORK_RECV_STATUS_DESYNC);
|
||||
return false;
|
||||
@@ -315,6 +345,14 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool ClientNetworkGameSocketHandler::EmergencySavePossible()
|
||||
{
|
||||
if (!my_client) return false;
|
||||
if (my_client->emergency_save_done) return false;
|
||||
my_client->emergency_save_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Our client's connection. */
|
||||
ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||
@@ -323,8 +361,14 @@ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nul
|
||||
static uint32 last_ack_frame;
|
||||
|
||||
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
||||
static uint32 _password_game_seed;
|
||||
/** The other bit of 'entropy' used to generate a salt for the company passwords. */
|
||||
static uint32 _company_password_game_seed;
|
||||
/** One bit of 'entropy' used to generate a salt for the server passwords. */
|
||||
static uint32 _server_password_game_seed;
|
||||
/** One bit of 'entropy' used to generate a salt for the rcon passwords. */
|
||||
static uint32 _rcon_password_game_seed;
|
||||
/** One bit of 'entropy' used to generate a salt for the settings passwords. */
|
||||
static uint32 _settings_password_game_seed;
|
||||
/** The other bit of 'entropy' used to generate a salt for the company, server, rcon, and settings passwords. */
|
||||
static char _password_server_id[NETWORK_SERVER_ID_LENGTH];
|
||||
|
||||
/** Maximum number of companies of the currently joined server. */
|
||||
@@ -392,7 +436,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
||||
p->Send_string(password);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _server_password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -404,7 +448,19 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *p
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the game password as requested.
|
||||
* @param password The game password.
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSettingsPassword(const char *password)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_SETTINGS_PASSWORD);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _settings_password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -502,7 +558,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const char *pa
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
||||
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -539,7 +595,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
||||
p->Send_string(pass);
|
||||
p->Send_string(GenerateCompanyPasswordHash(pass, _password_server_id, _rcon_password_game_seed));
|
||||
p->Send_string(command);
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
@@ -554,7 +610,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co
|
||||
{
|
||||
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
||||
p->Send_uint8(company);
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||
my_client->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -771,6 +827,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
this->status = STATUS_AUTH_GAME;
|
||||
|
||||
_server_password_game_seed = p->Recv_uint32();
|
||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
const char *password = _network_join_server_password;
|
||||
if (!StrEmpty(password)) {
|
||||
return SendGamePassword(password);
|
||||
@@ -786,7 +846,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
this->status = STATUS_AUTH_COMPANY;
|
||||
|
||||
_password_game_seed = p->Recv_uint32();
|
||||
_company_password_game_seed = p->Recv_uint32();
|
||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
@@ -808,7 +868,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet
|
||||
_network_own_client_id = (ClientID)p->Recv_uint32();
|
||||
|
||||
/* Initialize the password hash salting variables, even if they were previously. */
|
||||
_password_game_seed = p->Recv_uint32();
|
||||
_company_password_game_seed = p->Recv_uint32();
|
||||
_server_password_game_seed = p->Recv_uint32();
|
||||
_rcon_password_game_seed = p->Recv_uint32();
|
||||
_settings_password_game_seed = p->Recv_uint32();
|
||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||
|
||||
/* Start receiving the map */
|
||||
@@ -932,6 +995,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p)
|
||||
{
|
||||
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_frame_counter_server = p->Recv_uint32();
|
||||
@@ -945,6 +1009,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
_sync_seed_2 = p->Recv_uint32();
|
||||
#endif
|
||||
_sync_state_checksum = p->Recv_uint64();
|
||||
}
|
||||
#endif
|
||||
/* Receive the token. */
|
||||
@@ -965,6 +1030,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
||||
{
|
||||
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_sync_frame = p->Recv_uint32();
|
||||
@@ -972,12 +1038,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
_sync_seed_2 = p->Recv_uint32();
|
||||
#endif
|
||||
_sync_state_checksum = p->Recv_uint64();
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p)
|
||||
{
|
||||
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
CommandPacket cp;
|
||||
@@ -997,6 +1065,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
||||
{
|
||||
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH];
|
||||
@@ -1054,6 +1123,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
if (client_id == _network_own_client_id) return NETWORK_RECV_STATUS_OKAY; // do not try to clear our own client info
|
||||
|
||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||
if (ci != nullptr) {
|
||||
@@ -1066,6 +1136,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet *p)
|
||||
{
|
||||
uint size = p->Recv_uint16();
|
||||
this->server_desync_log.resize(this->server_desync_log.size() + size);
|
||||
p->Recv_binary(const_cast<char *>(this->server_desync_log.data() + this->server_desync_log.size() - size), size);
|
||||
DEBUG(net, 2, "Received %u bytes of server desync log", size);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
||||
{
|
||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
@@ -1195,6 +1274,17 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet *p)
|
||||
{
|
||||
if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
_network_settings_access = p->Recv_bool();
|
||||
|
||||
ReInitAllWindows();
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the connection's state, i.e. is the connection still up?
|
||||
*/
|
||||
@@ -1249,6 +1339,16 @@ void NetworkClientSendRcon(const char *password, const char *command)
|
||||
MyClient::SendRCon(password, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send settings password.
|
||||
* @param password The password.
|
||||
* @param command The command to execute.
|
||||
*/
|
||||
void NetworkClientSendSettingsPassword(const char *password)
|
||||
{
|
||||
MyClient::SendSettingsPassword(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the server of this client wanting to be moved to another company.
|
||||
* @param company_id id of the company the client wishes to be moved to.
|
||||
|
@@ -32,11 +32,16 @@ private:
|
||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||
STATUS_MAP, ///< The client is downloading the map.
|
||||
STATUS_ACTIVE, ///< The client is active within in the game.
|
||||
STATUS_CLOSING, ///< The client connection is in the process of being closed.
|
||||
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||
};
|
||||
|
||||
ServerStatus status; ///< Status of the connection with the server.
|
||||
|
||||
FILE *desync_log_file = nullptr;
|
||||
std::string server_desync_log;
|
||||
bool emergency_save_done = false;
|
||||
|
||||
protected:
|
||||
friend void NetworkExecuteLocalCommandQueue();
|
||||
friend void NetworkClose(bool close_admins);
|
||||
@@ -49,6 +54,7 @@ protected:
|
||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WAIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p) override;
|
||||
@@ -62,6 +68,7 @@ protected:
|
||||
NetworkRecvStatus Receive_SERVER_CHAT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_DESYNC_LOG(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p) override;
|
||||
NetworkRecvStatus Receive_SERVER_RCON(Packet *p) override;
|
||||
@@ -92,6 +99,7 @@ public:
|
||||
|
||||
static NetworkRecvStatus SendGamePassword(const char *password);
|
||||
static NetworkRecvStatus SendCompanyPassword(const char *password);
|
||||
static NetworkRecvStatus SendSettingsPassword(const char *password);
|
||||
|
||||
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data);
|
||||
static NetworkRecvStatus SendSetPassword(const char *password);
|
||||
@@ -104,6 +112,8 @@ public:
|
||||
static void Send();
|
||||
static bool Receive();
|
||||
static bool GameLoop();
|
||||
|
||||
static bool EmergencySavePossible();
|
||||
};
|
||||
|
||||
/** Helper to make the code look somewhat nicer. */
|
||||
|
@@ -54,6 +54,7 @@ void NetworkClientsToSpectators(CompanyID cid);
|
||||
void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr);
|
||||
void NetworkClientRequestMove(CompanyID company, const char *pass = "");
|
||||
void NetworkClientSendRcon(const char *password, const char *command);
|
||||
void NetworkClientSendSettingsPassword(const char *password);
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data = NetworkTextMessageData());
|
||||
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
|
||||
bool NetworkCompanyIsPassworded(CompanyID company_id);
|
||||
|
@@ -118,6 +118,7 @@ extern uint32 _sync_seed_1;
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
extern uint32 _sync_seed_2;
|
||||
#endif
|
||||
extern uint64 _sync_state_checksum;
|
||||
extern uint32 _sync_frame;
|
||||
extern bool _network_first_time;
|
||||
/* Vars needed for the join-GUI */
|
||||
|
@@ -216,6 +216,9 @@ 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;
|
||||
this->server_hash_bits = InteractiveRandom();
|
||||
this->rcon_hash_bits = InteractiveRandom();
|
||||
this->settings_hash_bits = InteractiveRandom();
|
||||
|
||||
/* The Socket and Info pools need to be the same in size. After all,
|
||||
* each Socket will be associated with at most one Info object. As
|
||||
@@ -320,7 +323,14 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
NetworkClientSocket *cs;
|
||||
FOR_ALL_CLIENT_SOCKETS(cs) {
|
||||
if (cs->writable) {
|
||||
if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
|
||||
if (cs->status == STATUS_CLOSE_PENDING) {
|
||||
SendPacketsState send_state = cs->SendPackets(true);
|
||||
if (send_state == SPS_CLOSED) {
|
||||
cs->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
} else if (send_state != SPS_PARTLY_SENT && send_state != SPS_NONE_SENT) {
|
||||
ShutdownSocket(cs->sock, true, false, 2);
|
||||
}
|
||||
} else if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
|
||||
/* This client is in the middle of a map-send, call the function for that */
|
||||
cs->SendMap();
|
||||
}
|
||||
@@ -461,6 +471,20 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
||||
{
|
||||
for (size_t offset = 0; offset < log.size();) {
|
||||
Packet *p = new Packet(PACKET_SERVER_DESYNC_LOG);
|
||||
size_t size = min<size_t>(log.size() - offset, SHRT_MAX - 2 - p->size);
|
||||
p->Send_uint16(size);
|
||||
p->Send_binary(log.data() + offset, size);
|
||||
this->SendPacket(p);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send the check for the NewGRFs. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
||||
{
|
||||
@@ -492,6 +516,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||
p->Send_string(_settings_client.network.network_id);
|
||||
this->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -531,6 +557,9 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
|
||||
p = new Packet(PACKET_SERVER_WELCOME);
|
||||
p->Send_uint32(this->client_id);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->rcon_hash_bits);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->settings_hash_bits);
|
||||
p->Send_string(_settings_client.network.network_id);
|
||||
this->SendPacket(p);
|
||||
|
||||
@@ -689,6 +718,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
p->Send_uint32(_sync_seed_2);
|
||||
#endif
|
||||
p->Send_uint64(_sync_state_checksum);
|
||||
#endif
|
||||
|
||||
/* If token equals 0, we need to make a new token and send that. */
|
||||
@@ -711,6 +741,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||
p->Send_uint32(_sync_seed_2);
|
||||
#endif
|
||||
p->Send_uint64(_sync_state_checksum);
|
||||
this->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -852,6 +883,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSettingsAccessUpdate(bool ok)
|
||||
{
|
||||
Packet *p = new Packet(PACKET_SERVER_SETTINGS_ACCESS);
|
||||
p->Send_bool(ok);
|
||||
this->SendPacket(p);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
|
||||
/***********
|
||||
* Receiving functions
|
||||
* DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
|
||||
@@ -970,7 +1010,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(P
|
||||
|
||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
||||
if (!StrEmpty(_settings_client.network.server_password) &&
|
||||
strcmp(password, _settings_client.network.server_password) != 0) {
|
||||
strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.server_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->server_hash_bits)) != 0) {
|
||||
/* Password is invalid */
|
||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||
}
|
||||
@@ -1006,6 +1046,29 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWOR
|
||||
return this->SendWelcome();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet *p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) {
|
||||
/* Illegal call, return error and ignore the packet */
|
||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
}
|
||||
|
||||
char password[NETWORK_PASSWORD_LENGTH];
|
||||
p->Recv_string(password, sizeof(password));
|
||||
|
||||
/* Check settings password. Deny if no password is set */
|
||||
if (StrEmpty(_settings_client.network.settings_password) ||
|
||||
strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.settings_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->settings_hash_bits)) != 0) {
|
||||
DEBUG(net, 0, "[settings-ctrl] wrong password from client-id %d", this->client_id);
|
||||
this->settings_authed = false;
|
||||
} else {
|
||||
DEBUG(net, 0, "[settings-ctrl] client-id %d", this->client_id);
|
||||
this->settings_authed = true;
|
||||
}
|
||||
|
||||
return this->SendSettingsAccessUpdate(this->settings_authed);
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
|
||||
{
|
||||
NetworkClientSocket *new_cs;
|
||||
@@ -1100,12 +1163,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
||||
}
|
||||
|
||||
|
||||
if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
|
||||
if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER && !this->settings_authed) {
|
||||
IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
||||
return this->SendError(NETWORK_ERROR_KICKED);
|
||||
}
|
||||
|
||||
if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
|
||||
if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER && !this->settings_authed) {
|
||||
IConsolePrintF(CC_ERROR, "WARNING: spectator issuing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
||||
return this->SendError(NETWORK_ERROR_KICKED);
|
||||
}
|
||||
@@ -1115,7 +1178,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
||||
* to match the company in the packet. If it doesn't, the client has done
|
||||
* something pretty naughty (or a bug), and will be kicked
|
||||
*/
|
||||
if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
|
||||
if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company &&
|
||||
!((GetCommandFlags(cp.cmd) & CMD_SERVER) && this->settings_authed)) {
|
||||
IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
|
||||
ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
|
||||
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
|
||||
@@ -1171,12 +1235,22 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
|
||||
NetworkAdminClientError(this->client_id, errorno);
|
||||
|
||||
if (errorno == NETWORK_ERROR_DESYNC) {
|
||||
CrashLog::DesyncCrashLog(&(this->desync_log), nullptr);
|
||||
std::string server_desync_log;
|
||||
CrashLog::DesyncCrashLog(&(this->desync_log), &server_desync_log, DesyncExtraInfo{});
|
||||
this->SendDesyncLog(server_desync_log);
|
||||
|
||||
// decrease the sync frequency for this point onwards
|
||||
_settings_client.network.sync_freq = min<uint16>(_settings_client.network.sync_freq, 16);
|
||||
|
||||
// have the server and all clients run some sanity checks
|
||||
NetworkSendCommand(0, 0, 0, CMD_DESYNC_CHECK, nullptr, nullptr, _local_company, 0);
|
||||
}
|
||||
|
||||
SendPacketsState send_state = this->SendPackets(true);
|
||||
if (send_state != SPS_CLOSED) {
|
||||
this->status = STATUS_CLOSE_PENDING;
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
}
|
||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||
}
|
||||
|
||||
@@ -1476,7 +1550,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
||||
p->Recv_string(pass, sizeof(pass));
|
||||
p->Recv_string(command, sizeof(command));
|
||||
|
||||
if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
|
||||
if (strcmp(pass, GenerateCompanyPasswordHash(_settings_client.network.rcon_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->rcon_hash_bits)) != 0) {
|
||||
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -1910,6 +1984,7 @@ void NetworkServer_Tick(bool send_frame)
|
||||
break;
|
||||
|
||||
case NetworkClientSocket::STATUS_MAP_WAIT:
|
||||
case NetworkClientSocket::STATUS_CLOSE_PENDING:
|
||||
/* This is an internal state where we do not wait
|
||||
* on the client to move to a different state. */
|
||||
break;
|
||||
@@ -1919,7 +1994,7 @@ void NetworkServer_Tick(bool send_frame)
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
|
||||
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE && cs->status != NetworkClientSocket::STATUS_CLOSE_PENDING) {
|
||||
/* Check if we can send command, and if we have anything in the queue */
|
||||
NetworkHandleCommandQueue(cs);
|
||||
|
||||
@@ -1981,7 +2056,8 @@ void NetworkServerShowStatusToConsole()
|
||||
"loading map",
|
||||
"map done",
|
||||
"ready",
|
||||
"active"
|
||||
"active",
|
||||
"close pending"
|
||||
};
|
||||
assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
|
||||
|
||||
|
@@ -29,6 +29,7 @@ protected:
|
||||
NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_ACK(Packet *p) override;
|
||||
@@ -63,6 +64,7 @@ public:
|
||||
STATUS_DONE_MAP, ///< The client has downloaded the map.
|
||||
STATUS_PRE_ACTIVE, ///< The client is catching up the delayed frames.
|
||||
STATUS_ACTIVE, ///< The client is active within in the game.
|
||||
STATUS_CLOSE_PENDING, ///< The client connection is pending closure.
|
||||
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period).
|
||||
};
|
||||
|
||||
@@ -72,6 +74,10 @@ public:
|
||||
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
|
||||
uint32 server_hash_bits; ///< Server password hash entropy bits
|
||||
uint32 rcon_hash_bits; ///< Rcon password hash entropy bits
|
||||
uint32 settings_hash_bits; ///< Settings password hash entropy bits
|
||||
bool settings_authed = false;///< Authorised to control all game settings
|
||||
|
||||
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
||||
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
|
||||
@@ -95,6 +101,7 @@ public:
|
||||
|
||||
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci);
|
||||
NetworkRecvStatus SendError(NetworkErrorCode error);
|
||||
NetworkRecvStatus SendDesyncLog(const std::string &log);
|
||||
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, NetworkTextMessageData data);
|
||||
NetworkRecvStatus SendJoin(ClientID client_id);
|
||||
NetworkRecvStatus SendFrame();
|
||||
@@ -102,6 +109,7 @@ public:
|
||||
NetworkRecvStatus SendCommand(const CommandPacket *cp);
|
||||
NetworkRecvStatus SendCompanyUpdate();
|
||||
NetworkRecvStatus SendConfigUpdate();
|
||||
NetworkRecvStatus SendSettingsAccessUpdate(bool ok);
|
||||
|
||||
static void Send();
|
||||
static void AcceptConnection(SOCKET s, const NetworkAddress &address);
|
||||
|
Reference in New Issue
Block a user