Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -60,6 +60,11 @@ INSTANTIATE_POOL_METHODS(NetworkClientSocket)
|
||||
/** Instantiate the listen sockets. */
|
||||
template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
|
||||
|
||||
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password); ///< Provides the password validation for the game's password.
|
||||
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler(_settings_client.network.server_authorized_keys); ///< Provides the authorized key handling for the game authentication.
|
||||
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler(_settings_client.network.rcon_authorized_keys); ///< Provides the authorized key validation for rcon.
|
||||
|
||||
|
||||
/** Writing a savegame directly to a number of packets. */
|
||||
struct PacketWriter : SaveFilter {
|
||||
ServerNetworkGameSocketHandler *cs; ///< Socket we are associated with.
|
||||
@@ -118,10 +123,9 @@ struct PacketWriter : SaveFilter {
|
||||
/**
|
||||
* Transfer all packets from here to the network's queue while holding
|
||||
* the lock on our mutex.
|
||||
* @param socket The network socket to write to.
|
||||
* @return True iff the last packet of the map has been sent.
|
||||
*/
|
||||
bool TransferToNetworkQueue(ServerNetworkGameSocketHandler *socket)
|
||||
bool TransferToNetworkQueue()
|
||||
{
|
||||
/* Unsafe check for the queue being empty or not. */
|
||||
if (this->packets.empty()) return false;
|
||||
@@ -130,7 +134,7 @@ struct PacketWriter : SaveFilter {
|
||||
|
||||
while (!this->packets.empty()) {
|
||||
bool last_packet = this->packets.front()->GetPacketType() == PACKET_SERVER_MAP_DONE;
|
||||
socket->SendPacket(std::move(this->packets.front()));
|
||||
this->cs->SendPacket(std::move(this->packets.front()));
|
||||
this->packets.pop_front();
|
||||
|
||||
if (last_packet) return true;
|
||||
@@ -139,23 +143,22 @@ struct PacketWriter : SaveFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Write(byte *buf, size_t size) override
|
||||
void Write(uint8_t *buf, size_t size) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
/* We want to abort the saving when the socket is closed. */
|
||||
if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
|
||||
|
||||
if (this->current == nullptr) this->current = std::make_unique<Packet>(PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||
if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
byte *bufe = buf + size;
|
||||
while (buf != bufe) {
|
||||
size_t written = this->current->Send_bytes(buf, bufe);
|
||||
buf += written;
|
||||
std::span<const uint8_t> to_write(buf, size);
|
||||
while (!to_write.empty()) {
|
||||
to_write = this->current->Send_bytes(to_write);
|
||||
|
||||
if (!this->current->CanWriteToPacket(1)) {
|
||||
this->packets.push_back(std::move(this->current));
|
||||
if (buf != bufe) this->current = std::make_unique<Packet>(PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||
if (!to_write.empty()) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,19 +167,19 @@ struct PacketWriter : SaveFilter {
|
||||
|
||||
void Finish() override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
/* We want to abort the saving when the socket is closed. */
|
||||
if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
/* Make sure the last packet is flushed. */
|
||||
if (this->current != nullptr) this->packets.push_back(std::move(this->current));
|
||||
|
||||
/* Add a packet stating that this is the end to the queue. */
|
||||
this->packets.push_back(std::make_unique<Packet>(PACKET_SERVER_MAP_DONE));
|
||||
this->packets.push_back(std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DONE));
|
||||
|
||||
/* Fast-track the size to the client. */
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_MAP_SIZE);
|
||||
auto p = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_SIZE);
|
||||
p->Send_uint32((uint32_t)this->total_size);
|
||||
this->packets.push_front(std::move(p));
|
||||
}
|
||||
@@ -215,6 +218,8 @@ ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler()
|
||||
this->savegame->Destroy();
|
||||
this->savegame = nullptr;
|
||||
}
|
||||
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<Packet> ServerNetworkGameSocketHandler::ReceivePacket()
|
||||
@@ -271,16 +276,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
|
||||
/* We just lost one client :( */
|
||||
if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
|
||||
extern byte _network_clients_connected;
|
||||
extern uint8_t _network_clients_connected;
|
||||
_network_clients_connected--;
|
||||
|
||||
this->SendPackets(true);
|
||||
|
||||
this->DeferDeletion();
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -290,7 +292,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
*/
|
||||
/* static */ bool ServerNetworkGameSocketHandler::AllowConnection()
|
||||
{
|
||||
extern byte _network_clients_connected;
|
||||
extern uint8_t _network_clients_connected;
|
||||
bool accept = _network_clients_connected < MAX_CLIENTS;
|
||||
|
||||
/* We can't go over the MAX_CLIENTS limit here. However, the
|
||||
@@ -328,10 +330,11 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
|
||||
Debug(net, 9, "client[{}] SendClientInfo(): client_id={}", this->client_id, ci->client_id);
|
||||
|
||||
if (ci->client_id != INVALID_CLIENT_ID) {
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CLIENT_INFO);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CLIENT_INFO);
|
||||
p->Send_uint32(ci->client_id);
|
||||
p->Send_uint8 (ci->client_playas);
|
||||
p->Send_string(ci->client_name);
|
||||
p->Send_string(ci->public_key);
|
||||
|
||||
this->SendPacket(std::move(p));
|
||||
}
|
||||
@@ -343,7 +346,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendGameInfo()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_GAME_INFO, TCP_MTU);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_GAME_INFO, TCP_MTU);
|
||||
SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo());
|
||||
|
||||
this->SendPacket(std::move(p));
|
||||
@@ -360,7 +363,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendError(): error={}", this->client_id, error);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_ERROR);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR);
|
||||
|
||||
p->Send_uint8(error);
|
||||
if (!reason.empty()) p->Send_string(reason);
|
||||
@@ -405,7 +408,18 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendNewGRFCheck()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
|
||||
/* Invalid packet when status is anything but STATUS_IDENTIFY. */
|
||||
if (this->status != STATUS_IDENTIFY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
|
||||
this->status = STATUS_NEWGRFS_CHECK;
|
||||
|
||||
if (_grfconfig == nullptr) {
|
||||
/* There are no NewGRFs, so they're welcome. */
|
||||
return this->SendWelcome();
|
||||
}
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
|
||||
const GRFConfig *c;
|
||||
uint grf_count = 0;
|
||||
|
||||
@@ -423,49 +437,40 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
||||
}
|
||||
|
||||
/** Request the game password. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendAuthRequest()
|
||||
{
|
||||
if (_settings_client.network.server_password.empty()) {
|
||||
/* Do not actually need a game password, continue with the company password. */
|
||||
return this->SendNeedCompanyPassword();
|
||||
}
|
||||
Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
|
||||
|
||||
Debug(net, 9, "client[{}] SendNeedGamePassword()", this->client_id);
|
||||
|
||||
/* Invalid packet when status is STATUS_AUTH_GAME or higher */
|
||||
if (this->status >= STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
/* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
|
||||
if (this->status != STATUS_INACTIVE && status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
|
||||
this->status = STATUS_AUTH_GAME;
|
||||
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEED_GAME_PASSWORD);
|
||||
if (this->authentication_handler == nullptr) {
|
||||
this->authentication_handler = NetworkAuthenticationServerHandler::Create(&_password_provider, &_authorized_key_handler);
|
||||
}
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST);
|
||||
this->authentication_handler->SendRequest(*p);
|
||||
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Request the company password. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
|
||||
/** Notify the client that the authentication has completed and tell that for the remainder of this socket encryption is enabled. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendEnableEncryption()
|
||||
{
|
||||
NetworkClientInfo *ci = this->GetInfo();
|
||||
if (!Company::IsValidID(ci->client_playas) || _network_company_states[ci->client_playas].password.empty()) {
|
||||
return this->SendWelcome();
|
||||
}
|
||||
Debug(net, 9, "client[{}] SendEnableEncryption()", this->client_id);
|
||||
|
||||
Debug(net, 9, "client[{}] SendNeedCompanyPassword()", this->client_id);
|
||||
/* Invalid packet when status is anything but STATUS_AUTH_GAME. */
|
||||
if (this->status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
/* Invalid packet when status is STATUS_AUTH_COMPANY or higher */
|
||||
if (this->status >= STATUS_AUTH_COMPANY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = AUTH_COMPANY", this->client_id);
|
||||
this->status = STATUS_AUTH_COMPANY;
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEED_COMPANY_PASSWORD);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||
p->Send_string(_settings_client.network.network_id);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ENABLE_ENCRYPTION);
|
||||
this->authentication_handler->SendEnableEncryption(*p);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -475,20 +480,19 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendWelcome()", this->client_id);
|
||||
|
||||
/* Invalid packet when status is AUTH or higher */
|
||||
if (this->status >= STATUS_AUTHORIZED) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
/* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
|
||||
if (this->status != STATUS_NEWGRFS_CHECK) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = AUTHORIZED", this->client_id);
|
||||
this->status = STATUS_AUTHORIZED;
|
||||
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
_network_game_info.clients_on++;
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_WELCOME);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_WELCOME);
|
||||
p->Send_uint32(this->client_id);
|
||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||
p->Send_string(_settings_client.network.network_id);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
/* Transmit info about all the active clients */
|
||||
@@ -514,7 +518,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
|
||||
if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
|
||||
}
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_WAIT);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_WAIT);
|
||||
p->Send_uint8(waiting);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
@@ -564,7 +568,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
|
||||
this->savegame = std::make_shared<PacketWriter>(this);
|
||||
|
||||
/* Now send the _frame_counter and how many packets are coming */
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_MAP_BEGIN);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_MAP_BEGIN);
|
||||
p->Send_uint32(_frame_counter);
|
||||
this->SendPacket(std::move(p));
|
||||
|
||||
@@ -580,7 +584,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
|
||||
}
|
||||
|
||||
if (this->status == STATUS_MAP) {
|
||||
bool last_packet = this->savegame->TransferToNetworkQueue(this);
|
||||
bool last_packet = this->savegame->TransferToNetworkQueue();
|
||||
if (last_packet) {
|
||||
Debug(net, 9, "client[{}] SendMap(): last_packet", this->client_id);
|
||||
|
||||
@@ -607,7 +611,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendJoin(): client_id={}", this->client_id, client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_JOIN);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_JOIN);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
|
||||
@@ -618,7 +622,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
|
||||
/** Tell the client that they may run to a particular frame. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
||||
{
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_FRAME);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_FRAME);
|
||||
p->Send_uint32(_frame_counter);
|
||||
p->Send_uint32(_frame_counter_max);
|
||||
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
|
||||
@@ -643,7 +647,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendSync(), frame_counter={}, sync_seed_1={}", this->client_id, _frame_counter, _sync_seed_1);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_SYNC);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_SYNC);
|
||||
p->Send_uint32(_frame_counter);
|
||||
p->Send_uint32(_sync_seed_1);
|
||||
|
||||
@@ -662,7 +666,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacke
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendCommand(): cmd={}", this->client_id, cp.cmd);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_COMMAND);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMMAND);
|
||||
|
||||
this->NetworkGameSocketHandler::SendCommand(*p, cp);
|
||||
p->Send_uint32(cp.frame);
|
||||
@@ -686,7 +690,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action,
|
||||
|
||||
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CHAT);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHAT);
|
||||
|
||||
p->Send_uint8 (action);
|
||||
p->Send_uint32(client_id);
|
||||
@@ -711,7 +715,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(const std::st
|
||||
|
||||
if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_EXTERNAL_CHAT);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_EXTERNAL_CHAT);
|
||||
|
||||
p->Send_string(source);
|
||||
p->Send_uint16(colour);
|
||||
@@ -731,7 +735,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendErrorQuit(): client_id={}, errorno={}", this->client_id, client_id, errorno);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_ERROR_QUIT);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR_QUIT);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
p->Send_uint8 (errorno);
|
||||
@@ -748,7 +752,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendQuit(): client_id={}", this->client_id, client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_QUIT);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_QUIT);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
|
||||
@@ -761,7 +765,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendShutdown()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_SHUTDOWN);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_SHUTDOWN);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -771,7 +775,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendNewGame()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_NEWGAME);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEWGAME);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -785,7 +789,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendRConResult()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_RCON);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON);
|
||||
|
||||
p->Send_uint16(colour);
|
||||
p->Send_string(command);
|
||||
@@ -802,7 +806,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, C
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendMove(): client_id={}", this->client_id, client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_MOVE);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_MOVE);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
p->Send_uint8(company_id);
|
||||
@@ -810,25 +814,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, C
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send an update about the company password states. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendCompanyUpdate()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_COMPANY_UPDATE);
|
||||
|
||||
static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t));
|
||||
p->Send_uint16(_network_company_passworded);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Send an update about the max company/spectator counts. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendConfigUpdate()", this->client_id);
|
||||
|
||||
auto p = std::make_unique<Packet>(PACKET_SERVER_CONFIG_UPDATE);
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CONFIG_UPDATE);
|
||||
|
||||
p->Send_uint8(_settings_client.network.max_companies);
|
||||
p->Send_string(_settings_client.network.server_name);
|
||||
@@ -856,7 +847,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_NEWGRFS_CHECKED()", this->client_id);
|
||||
|
||||
return this->SendNeedGamePassword();
|
||||
return this->SendWelcome();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||
@@ -882,6 +873,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||
return this->SendError(NETWORK_ERROR_WRONG_REVISION);
|
||||
}
|
||||
|
||||
return this->SendAuthRequest();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_IDENTIFY) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_IDENTIFY()", this->client_id);
|
||||
|
||||
std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
|
||||
CompanyID playas = (Owner)p.Recv_uint8();
|
||||
p.Recv_uint8(); // former client_lang now 0
|
||||
@@ -905,10 +905,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||
break;
|
||||
case COMPANY_SPECTATOR: // Spectator
|
||||
break;
|
||||
default: // Join another company (companies 1-8 (index 0-7))
|
||||
default: // Join another company (companies 1..MAX_COMPANIES (index 0..(MAX_COMPANIES-1)))
|
||||
if (!Company::IsValidHumanID(playas)) {
|
||||
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
|
||||
}
|
||||
|
||||
if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) {
|
||||
/* When we're not authorized, just bump us to a spectator. */
|
||||
playas = COMPANY_SPECTATOR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -930,63 +935,65 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||
ci->join_date = TimerGameEconomy::date;
|
||||
ci->client_name = client_name;
|
||||
ci->client_playas = playas;
|
||||
ci->public_key = this->peer_public_key;
|
||||
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)ci->client_playas, (int)ci->index);
|
||||
|
||||
/* Make sure companies to which people try to join are not autocleaned */
|
||||
if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
|
||||
|
||||
Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
|
||||
this->status = STATUS_NEWGRFS_CHECK;
|
||||
|
||||
if (_grfconfig == nullptr) {
|
||||
/* Continue asking for the game password. */
|
||||
return this->SendNeedGamePassword();
|
||||
}
|
||||
Company *c = Company::GetIfValid(playas);
|
||||
if (c != nullptr) c->months_empty = 0;
|
||||
|
||||
return this->SendNewGRFCheck();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &p)
|
||||
static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
|
||||
{
|
||||
switch (method) {
|
||||
case NETWORK_AUTH_METHOD_X25519_PAKE:
|
||||
return NETWORK_ERROR_WRONG_PASSWORD;
|
||||
case NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY:
|
||||
return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_AUTH_GAME) {
|
||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
}
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_GAME_PASSWORD()", this->client_id);
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_AUTH_RESPONSE()", this->client_id);
|
||||
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
|
||||
switch (this->authentication_handler->ReceiveResponse(p)) {
|
||||
case NetworkAuthenticationServerHandler::AUTHENTICATED:
|
||||
break;
|
||||
|
||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
||||
if (!_settings_client.network.server_password.empty() &&
|
||||
_settings_client.network.server_password.compare(password) != 0) {
|
||||
/* Password is invalid */
|
||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||
case NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD:
|
||||
return this->SendAuthRequest();
|
||||
|
||||
case NetworkAuthenticationServerHandler::NOT_AUTHENTICATED:
|
||||
default:
|
||||
return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
|
||||
}
|
||||
|
||||
return this->SendNeedCompanyPassword();
|
||||
}
|
||||
NetworkRecvStatus status = this->SendEnableEncryption();
|
||||
if (status != NETWORK_RECV_STATUS_OKAY) return status;
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_AUTH_COMPANY) {
|
||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
}
|
||||
this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
|
||||
this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
|
||||
this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
|
||||
this->authentication_handler = nullptr;
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_COMPANY_PASSWORD()", this->client_id);
|
||||
Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
|
||||
this->status = STATUS_IDENTIFY;
|
||||
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
/* Check company password. Allow joining if we cleared the password meanwhile.
|
||||
* Also, check the company is still valid - client could be moved to spectators
|
||||
* in the middle of the authorization process */
|
||||
CompanyID playas = this->GetInfo()->client_playas;
|
||||
if (Company::IsValidID(playas) && !_network_company_states[playas].password.empty() &&
|
||||
_network_company_states[playas].password.compare(password) != 0) {
|
||||
/* Password is invalid */
|
||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||
}
|
||||
|
||||
return this->SendWelcome();
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet &)
|
||||
@@ -1050,10 +1057,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet &
|
||||
NetworkAdminClientInfo(this, true);
|
||||
|
||||
/* also update the new client with our max values */
|
||||
this->SendConfigUpdate();
|
||||
|
||||
/* quickly update the syncing client with company details */
|
||||
return this->SendCompanyUpdate();
|
||||
return this->SendConfigUpdate();
|
||||
}
|
||||
|
||||
/* Wrong status for this packet, give a warning to client, and close connection */
|
||||
@@ -1125,6 +1129,24 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
||||
}
|
||||
}
|
||||
|
||||
if (cp.cmd == CMD_COMPANY_ALLOW_LIST_CTRL) {
|
||||
/* Maybe the client just got moved before allowing? */
|
||||
if (ci->client_id != CLIENT_ID_SERVER && ci->client_playas != cp.company) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
/* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
|
||||
std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_ALLOW_LIST_CTRL>::Args>(cp.data));
|
||||
bool found = false;
|
||||
for (const NetworkClientInfo *info : NetworkClientInfo::Iterate()) {
|
||||
if (info->public_key == public_key) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Maybe the client just left? */
|
||||
if (!found) return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) NetworkReplaceCommandClientId(cp, this->client_id);
|
||||
|
||||
this->incoming_queue.push_back(cp);
|
||||
@@ -1401,22 +1423,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet &p)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) {
|
||||
/* Illegal call, return error and ignore the packet */
|
||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
}
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_SET_PASSWORD()", this->client_id);
|
||||
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
const NetworkClientInfo *ci = this->GetInfo();
|
||||
|
||||
NetworkServerSetCompanyPassword(ci->client_playas, password);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) {
|
||||
@@ -1455,14 +1461,16 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
|
||||
if (_settings_client.network.rcon_password.empty()) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_RCON()", this->client_id);
|
||||
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
|
||||
|
||||
if (_settings_client.network.rcon_password.compare(password) != 0) {
|
||||
if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
|
||||
/* We are allowed, nothing more to validate. */
|
||||
} else if (_settings_client.network.rcon_password.empty()) {
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
} else if (_settings_client.network.rcon_password.compare(password) != 0) {
|
||||
Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
@@ -1486,16 +1494,9 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &p)
|
||||
/* Check if the company is valid, we don't allow moving to AI companies */
|
||||
if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
/* Check if we require a password for this company */
|
||||
if (company_id != COMPANY_SPECTATOR && !_network_company_states[company_id].password.empty()) {
|
||||
/* we need a password from the client - should be in this packet */
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
|
||||
/* Incorrect password sent, return! */
|
||||
if (_network_company_states[company_id].password.compare(password) != 0) {
|
||||
Debug(net, 2, "Wrong password from client-id #{} for company #{}", this->client_id, company_id + 1);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) {
|
||||
Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/* if we get here we can move the client */
|
||||
@@ -1514,7 +1515,7 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
|
||||
/* Go through all vehicles and count the type of vehicles */
|
||||
for (const Vehicle *v : Vehicle::Iterate()) {
|
||||
if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
|
||||
byte type = 0;
|
||||
uint8_t type = 0;
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
|
||||
case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
|
||||
@@ -1560,11 +1561,10 @@ void NetworkUpdateClientInfo(ClientID client_id)
|
||||
NetworkAdminClientUpdate(ci);
|
||||
}
|
||||
|
||||
/** Check if the server has autoclean_companies activated
|
||||
* Two things happen:
|
||||
* 1) If a company is not protected, it is closed after 1 year (for example)
|
||||
* 2) If a company is protected, protection is disabled after 3 years (for example)
|
||||
* (and item 1. happens a year later)
|
||||
/**
|
||||
* Remove companies that have not been used depending on the \c autoclean_companies setting
|
||||
* and values for \c autoclean_protected, which removes any company, and
|
||||
* \c autoclean_novehicles, which removes companies without vehicles.
|
||||
*/
|
||||
static void NetworkAutoCleanCompanies()
|
||||
{
|
||||
@@ -1591,37 +1591,29 @@ static void NetworkAutoCleanCompanies()
|
||||
}
|
||||
|
||||
/* Go through all the companies */
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
for (Company *c : Company::Iterate()) {
|
||||
/* Skip the non-active once */
|
||||
if (c->is_ai) continue;
|
||||
|
||||
if (!HasBit(has_clients, c->index)) {
|
||||
/* The company is empty for one month more */
|
||||
_network_company_states[c->index].months_empty++;
|
||||
if (c->months_empty != std::numeric_limits<decltype(c->months_empty)>::max()) c->months_empty++;
|
||||
|
||||
/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
|
||||
if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && _network_company_states[c->index].password.empty()) {
|
||||
/* Is the company empty for autoclean_protected-months? */
|
||||
if (_settings_client.network.autoclean_protected != 0 && c->months_empty > _settings_client.network.autoclean_protected) {
|
||||
/* Shut the company down */
|
||||
Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
|
||||
IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no password.", c->index + 1);
|
||||
}
|
||||
/* Is the company empty for autoclean_protected-months, and there is a protection? */
|
||||
if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !_network_company_states[c->index].password.empty()) {
|
||||
/* Unprotect the company */
|
||||
_network_company_states[c->index].password.clear();
|
||||
IConsolePrint(CC_INFO, "Auto-removed protection from company #{}.", c->index + 1);
|
||||
_network_company_states[c->index].months_empty = 0;
|
||||
NetworkServerUpdateCompanyPassworded(c->index, false);
|
||||
IConsolePrint(CC_INFO, "Auto-cleaned company #{}.", c->index + 1);
|
||||
}
|
||||
/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
|
||||
if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && !HasBit(has_vehicles, c->index)) {
|
||||
if (_settings_client.network.autoclean_novehicles != 0 && c->months_empty > _settings_client.network.autoclean_novehicles && !HasBit(has_vehicles, c->index)) {
|
||||
/* Shut the company down */
|
||||
Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
|
||||
IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
|
||||
}
|
||||
} else {
|
||||
/* It is not empty, reset the date */
|
||||
_network_company_states[c->index].months_empty = 0;
|
||||
c->months_empty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1688,25 +1680,6 @@ bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_na
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/Reset a company password on the server end.
|
||||
* @param company_id ID of the company the password should be changed for.
|
||||
* @param password The new password.
|
||||
* @param already_hashed Is the given password already hashed?
|
||||
*/
|
||||
void NetworkServerSetCompanyPassword(CompanyID company_id, const std::string &password, bool already_hashed)
|
||||
{
|
||||
if (!Company::IsValidHumanID(company_id)) return;
|
||||
|
||||
if (already_hashed) {
|
||||
_network_company_states[company_id].password = password;
|
||||
} else {
|
||||
_network_company_states[company_id].password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed);
|
||||
}
|
||||
|
||||
NetworkServerUpdateCompanyPassworded(company_id, !_network_company_states[company_id].password.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the command-queue of a socket.
|
||||
* @param cs The socket to handle the queue for.
|
||||
@@ -1779,6 +1752,7 @@ void NetworkServer_Tick(bool send_frame)
|
||||
break;
|
||||
|
||||
case NetworkClientSocket::STATUS_INACTIVE:
|
||||
case NetworkClientSocket::STATUS_IDENTIFY:
|
||||
case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
|
||||
case NetworkClientSocket::STATUS_AUTHORIZED:
|
||||
/* NewGRF check and authorized states should be handled almost instantly.
|
||||
@@ -1825,7 +1799,6 @@ void NetworkServer_Tick(bool send_frame)
|
||||
break;
|
||||
|
||||
case NetworkClientSocket::STATUS_AUTH_GAME:
|
||||
case NetworkClientSocket::STATUS_AUTH_COMPANY:
|
||||
/* These don't block? */
|
||||
if (lag > _settings_client.network.max_password_time) {
|
||||
IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to enter the password.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_password_time);
|
||||
@@ -1971,9 +1944,9 @@ void NetworkServerShowStatusToConsole()
|
||||
{
|
||||
static const char * const stat_str[] = {
|
||||
"inactive",
|
||||
"authorizing",
|
||||
"identifing client",
|
||||
"checking NewGRFs",
|
||||
"authorizing (server password)",
|
||||
"authorizing (company password)",
|
||||
"authorized",
|
||||
"waiting",
|
||||
"loading map",
|
||||
@@ -2013,25 +1986,6 @@ void NetworkServerUpdateGameInfo()
|
||||
if (_network_server) FillStaticNetworkServerGameInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell that a particular company is (not) passworded.
|
||||
* @param company_id The company that got/removed the password.
|
||||
* @param passworded Whether the password was received or removed.
|
||||
*/
|
||||
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded)
|
||||
{
|
||||
if (NetworkCompanyIsPassworded(company_id) == passworded) return;
|
||||
|
||||
SB(_network_company_passworded, company_id, 1, !!passworded);
|
||||
SetWindowClassesDirty(WC_COMPANY);
|
||||
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendCompanyUpdate();
|
||||
}
|
||||
|
||||
NetworkAdminCompanyUpdate(Company::GetIfValid(company_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the tid-bits of moving a client from one company to another.
|
||||
* @param client_id id of the client we want to move.
|
||||
@@ -2190,6 +2144,18 @@ void NetworkPrintClients()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public key of the client with the given id.
|
||||
* @param client_id The id of the client.
|
||||
* @return View of the public key, which is empty when the client does not exist.
|
||||
*/
|
||||
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
|
||||
{
|
||||
auto socket = NetworkClientSocket::GetByClientID(client_id);
|
||||
return socket == nullptr ? "" : socket->GetPeerPublicKey();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform all the server specific administration of a new company.
|
||||
* @param c The newly created company; can't be nullptr.
|
||||
@@ -2201,21 +2167,20 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
|
||||
|
||||
if (!_network_server) return;
|
||||
|
||||
_network_company_states[c->index].months_empty = 0;
|
||||
_network_company_states[c->index].password.clear();
|
||||
NetworkServerUpdateCompanyPassworded(c->index, false);
|
||||
|
||||
if (ci != nullptr) {
|
||||
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
|
||||
ci->client_playas = c->index;
|
||||
NetworkUpdateClientInfo(ci->client_id);
|
||||
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
|
||||
}
|
||||
|
||||
if (ci != nullptr) {
|
||||
/* ci is nullptr when replaying, or for AIs. In neither case there is a client.
|
||||
We need to send Admin port update here so that they first know about the new company
|
||||
and then learn about a possibly joining client (see FS#6025) */
|
||||
/*
|
||||
* This function is called from a command, but is only called for the server.
|
||||
* The client information is managed out-of-band from the commands, so to not have a
|
||||
* different state/president/company name in the different clients, we need to
|
||||
* circumvent the normal ::Post logic and go directly to sending the command.
|
||||
*/
|
||||
Command<CMD_COMPANY_ALLOW_LIST_CTRL>::SendNet(STR_NULL, c->index, CALCA_ADD, ci->public_key);
|
||||
Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
|
||||
|
||||
NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user