2009-08-21 22:21:05 +02:00
/*
* This file is part of OpenTTD .
* OpenTTD is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , version 2.
* OpenTTD is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with OpenTTD . If not , see < http : //www.gnu.org/licenses/>.
*/
2008-05-06 17:11:33 +02:00
/** @file network_server.cpp Server part of the network protocol. */
2007-01-02 18:34:03 +01:00
# include "../stdafx.h"
2007-12-21 20:49:27 +01:00
# include "../strings_func.h"
2023-09-02 19:46:52 +02:00
# include "core/network_game_info.h"
2010-10-17 19:36:23 +02:00
# include "network_admin.h"
2004-12-04 18:54:56 +01:00
# include "network_server.h"
2004-12-15 21:10:34 +01:00
# include "network_udp.h"
2010-01-15 17:41:15 +01:00
# include "network_base.h"
2008-05-24 12:15:06 +02:00
# include "../console_func.h"
2010-01-15 17:41:15 +01:00
# include "../company_base.h"
2007-12-21 22:50:46 +01:00
# include "../command_func.h"
2009-01-04 16:32:25 +01:00
# include "../saveload/saveload.h"
2010-12-05 15:45:52 +01:00
# include "../saveload/saveload_filter.h"
2008-03-31 02:06:17 +02:00
# include "../station_base.h"
2007-01-02 18:34:03 +01:00
# include "../genworld.h"
2008-09-30 22:51:04 +02:00
# include "../company_func.h"
# include "../company_gui.h"
2021-10-28 23:48:26 +02:00
# include "../company_cmd.h"
2009-12-02 18:37:02 +01:00
# include "../roadveh.h"
2010-10-15 15:22:00 +02:00
# include "../order_backup.h"
2010-10-15 21:58:56 +02:00
# include "../core/pool_func.hpp"
2010-11-30 15:18:20 +01:00
# include "../core/random_func.hpp"
2021-10-31 19:39:09 +01:00
# include "../company_cmd.h"
2010-01-15 00:06:41 +01:00
# include "../rev.h"
2023-04-13 13:56:00 +02:00
# include "../timer/timer.h"
# include "../timer/timer_game_calendar.h"
2024-01-22 15:04:34 +01:00
# include "../timer/timer_game_economy.h"
2024-01-26 16:25:25 +01:00
# include "../timer/timer_game_realtime.h"
2019-03-11 00:45:39 +01:00
# include <mutex>
# include <condition_variable>
2004-12-04 18:54:56 +01:00
2014-04-23 22:13:33 +02:00
# include "../safeguards.h"
2008-01-13 02:21:35 +01:00
2009-03-15 01:32:18 +01:00
/* This file handles all the server-commands */
2004-12-04 18:54:56 +01:00
2010-10-15 15:22:00 +02:00
DECLARE_POSTFIX_INCREMENT ( ClientID )
/** The identifier counter for new clients (is never decreased) */
static ClientID _network_client_id = CLIENT_ID_FIRST ;
2010-10-15 21:58:56 +02:00
/** Make very sure the preconditions given in network_type.h are actually followed */
2020-12-27 11:44:22 +01:00
static_assert ( MAX_CLIENT_SLOTS > MAX_CLIENTS ) ;
2011-05-05 18:24:48 +02:00
/** Yes... */
2020-12-27 11:44:22 +01:00
static_assert ( NetworkClientSocketPool : : MAX_SIZE = = MAX_CLIENT_SLOTS ) ;
2010-10-15 21:58:56 +02:00
2011-05-05 18:24:48 +02:00
/** The pool with clients. */
2010-10-15 21:58:56 +02:00
NetworkClientSocketPool _networkclientsocket_pool ( " NetworkClientSocket " ) ;
INSTANTIATE_POOL_METHODS ( NetworkClientSocket )
2010-10-15 23:56:06 +02:00
/** Instantiate the listen sockets. */
template SocketList TCPListenHandler < ServerNetworkGameSocketHandler , PACKET_SERVER_FULL , PACKET_SERVER_BANNED > : : sockets ;
2010-12-05 15:45:52 +01:00
/** Writing a savegame directly to a number of packets. */
struct PacketWriter : SaveFilter {
ServerNetworkGameSocketHandler * cs ; ///< Socket we are associated with.
Packet * current ; ///< The packet we're currently writing to.
size_t total_size ; ///< Total size of the compressed savegame.
2013-11-15 23:22:01 +01:00
Packet * packets ; ///< Packet queue of the savegame; send these "slowly" to the client.
2019-03-11 00:45:39 +01:00
std : : mutex mutex ; ///< Mutex for making threaded saving safe.
std : : condition_variable exit_sig ; ///< Signal for threaded destruction of this packet writer.
2010-12-05 15:45:52 +01:00
/**
* Create the packet writer .
* @ param cs The socket handler we ' re making the packets for .
*/
2019-04-10 23:07:06 +02:00
PacketWriter ( ServerNetworkGameSocketHandler * cs ) : SaveFilter ( nullptr ) , cs ( cs ) , current ( nullptr ) , total_size ( 0 ) , packets ( nullptr )
2010-12-05 15:45:52 +01:00
{
}
/** Make sure everything is cleaned up. */
~ PacketWriter ( )
{
2019-03-11 00:45:39 +01:00
std : : unique_lock < std : : mutex > lock ( this - > mutex ) ;
2013-11-15 23:22:01 +01:00
2019-04-10 23:07:06 +02:00
if ( this - > cs ! = nullptr ) this - > exit_sig . wait ( lock ) ;
2013-11-15 23:22:01 +01:00
/* This must all wait until the Destroy function is called. */
2019-04-10 23:07:06 +02:00
while ( this - > packets ! = nullptr ) {
2021-04-20 18:50:46 +02:00
delete Packet : : PopFromQueue ( & this - > packets ) ;
2010-12-05 15:48:39 +01:00
}
2010-12-05 15:45:52 +01:00
delete this - > current ;
2013-11-15 23:22:01 +01:00
}
/**
* Begin the destruction of this packet writer . It can happen in two ways :
* in the first case the client disconnected while saving the map . In this
* case the saving has not finished and killed this PacketWriter . In that
2019-04-10 23:07:06 +02:00
* case we simply set cs to nullptr , triggering the appending to fail due to
2013-11-15 23:22:01 +01:00
* the connection problem and eventually triggering the destructor . In the
* second case the destructor is already called , and it is waiting for our
* signal which we will send . Only then the packets will be removed by the
* destructor .
*/
void Destroy ( )
{
2019-03-11 00:45:39 +01:00
std : : unique_lock < std : : mutex > lock ( this - > mutex ) ;
2013-11-15 23:22:01 +01:00
2019-04-10 23:07:06 +02:00
this - > cs = nullptr ;
2013-11-15 23:22:01 +01:00
2019-03-11 00:45:39 +01:00
this - > exit_sig . notify_all ( ) ;
lock . unlock ( ) ;
2013-11-21 19:35:31 +01:00
/* Make sure the saving is completely cancelled. Yes,
* we need to handle the save finish as well as the
* next connection might just be requesting a map . */
WaitTillSaved ( ) ;
2013-11-15 23:22:01 +01:00
}
/**
2021-04-25 19:59:19 +02:00
* 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 .
2013-11-15 23:22:01 +01:00
*/
2021-04-25 19:59:19 +02:00
bool TransferToNetworkQueue ( ServerNetworkGameSocketHandler * socket )
2013-11-15 23:22:01 +01:00
{
2021-04-25 19:59:19 +02:00
/* Unsafe check for the queue being empty or not. */
if ( this - > packets = = nullptr ) return false ;
2013-11-15 23:22:01 +01:00
2019-03-11 00:45:39 +01:00
std : : lock_guard < std : : mutex > lock ( this - > mutex ) ;
2013-11-15 23:22:01 +01:00
2021-04-25 19:59:19 +02:00
while ( this - > packets ! = nullptr ) {
Packet * p = Packet : : PopFromQueue ( & this - > packets ) ;
bool last_packet = p - > GetPacketType ( ) = = PACKET_SERVER_MAP_DONE ;
socket - > SendPacket ( p ) ;
if ( last_packet ) return true ;
}
return false ;
2010-12-05 15:45:52 +01:00
}
/** Append the current packet to the queue. */
void AppendQueue ( )
{
2019-04-10 23:07:06 +02:00
if ( this - > current = = nullptr ) return ;
2010-12-05 15:45:52 +01:00
2021-04-20 18:50:46 +02:00
Packet : : AddToQueue ( & this - > packets , this - > current ) ;
2019-04-10 23:07:06 +02:00
this - > current = nullptr ;
2010-12-05 15:45:52 +01:00
}
2020-06-18 18:23:50 +02:00
/** Prepend the current packet to the queue. */
void PrependQueue ( )
{
if ( this - > current = = nullptr ) return ;
2021-04-20 18:50:46 +02:00
/* Reversed from AppendQueue so the queue gets added to the current one. */
Packet : : AddToQueue ( & this - > current , this - > packets ) ;
2020-06-18 18:23:50 +02:00
this - > packets = this - > current ;
this - > current = nullptr ;
}
2019-03-03 23:25:13 +01:00
void Write ( byte * buf , size_t size ) override
2010-12-05 15:45:52 +01:00
{
2011-02-12 00:20:35 +01:00
/* We want to abort the saving when the socket is closed. */
2019-04-10 23:07:06 +02:00
if ( this - > cs = = nullptr ) SlError ( STR_NETWORK_ERROR_LOSTCONNECTION ) ;
2010-12-05 15:45:52 +01:00
2021-04-18 14:56:25 +02:00
if ( this - > current = = nullptr ) this - > current = new Packet ( PACKET_SERVER_MAP_DATA , TCP_MTU ) ;
2010-12-05 15:45:52 +01:00
2019-03-11 00:45:39 +01:00
std : : lock_guard < std : : mutex > lock ( this - > mutex ) ;
2010-12-05 15:48:39 +01:00
2010-12-05 15:45:52 +01:00
byte * bufe = buf + size ;
while ( buf ! = bufe ) {
2021-04-18 10:49:12 +02:00
size_t written = this - > current - > Send_bytes ( buf , bufe ) ;
buf + = written ;
2010-12-05 15:45:52 +01:00
2021-04-18 10:49:12 +02:00
if ( ! this - > current - > CanWriteToPacket ( 1 ) ) {
2010-12-05 15:45:52 +01:00
this - > AppendQueue ( ) ;
2021-04-18 14:56:25 +02:00
if ( buf ! = bufe ) this - > current = new Packet ( PACKET_SERVER_MAP_DATA , TCP_MTU ) ;
2010-12-05 15:45:52 +01:00
}
}
this - > total_size + = size ;
}
2019-03-03 23:25:13 +01:00
void Finish ( ) override
2010-12-05 15:45:52 +01:00
{
2011-02-12 00:20:35 +01:00
/* We want to abort the saving when the socket is closed. */
2019-04-10 23:07:06 +02:00
if ( this - > cs = = nullptr ) SlError ( STR_NETWORK_ERROR_LOSTCONNECTION ) ;
2010-12-05 15:48:39 +01:00
2019-03-11 00:45:39 +01:00
std : : lock_guard < std : : mutex > lock ( this - > mutex ) ;
2010-12-05 15:48:39 +01:00
2010-12-05 15:45:52 +01:00
/* Make sure the last packet is flushed. */
this - > AppendQueue ( ) ;
/* Add a packet stating that this is the end to the queue. */
this - > current = new Packet ( PACKET_SERVER_MAP_DONE ) ;
this - > AppendQueue ( ) ;
/* Fast-track the size to the client. */
2020-06-18 18:23:50 +02:00
this - > current = new Packet ( PACKET_SERVER_MAP_SIZE ) ;
2023-05-08 19:01:06 +02:00
this - > current - > Send_uint32 ( ( uint32_t ) this - > total_size ) ;
2020-06-18 18:23:50 +02:00
this - > PrependQueue ( ) ;
2010-12-05 15:45:52 +01:00
}
} ;
2010-10-15 15:22:00 +02:00
/**
* Create a new socket for the server side of the game connection .
* @ param s The socket to connect with .
*/
ServerNetworkGameSocketHandler : : ServerNetworkGameSocketHandler ( SOCKET s ) : NetworkGameSocketHandler ( s )
{
2010-10-15 22:29:59 +02:00
this - > status = STATUS_INACTIVE ;
2010-10-15 15:22:00 +02:00
this - > client_id = _network_client_id + + ;
2010-11-30 21:01:26 +01:00
this - > receive_limit = _settings_client . network . bytes_per_frame_burst ;
2011-02-08 22:47:10 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = INACTIVE " , this - > client_id ) ;
2011-02-08 22:47:10 +01:00
/* 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
* such if the Socket was allocated the Info object can as well . */
2020-12-27 11:44:22 +01:00
static_assert ( NetworkClientSocketPool : : MAX_SIZE = = NetworkClientInfoPool : : MAX_SIZE ) ;
2010-10-15 15:22:00 +02:00
}
/**
* Clear everything related to this client .
*/
ServerNetworkGameSocketHandler : : ~ ServerNetworkGameSocketHandler ( )
{
2023-06-16 21:54:04 +02:00
delete this - > GetInfo ( ) ;
2010-10-15 15:22:00 +02:00
if ( _redirect_console_to_client = = this - > client_id ) _redirect_console_to_client = INVALID_CLIENT_ID ;
OrderBackup : : ResetUser ( this - > client_id ) ;
2010-12-05 15:48:39 +01:00
2019-04-10 23:07:06 +02:00
if ( this - > savegame ! = nullptr ) {
2013-11-15 23:22:01 +01:00
this - > savegame - > Destroy ( ) ;
2019-04-10 23:07:06 +02:00
this - > savegame = nullptr ;
2013-11-15 23:22:01 +01:00
}
2010-10-15 15:22:00 +02:00
}
2010-11-30 21:01:26 +01:00
Packet * ServerNetworkGameSocketHandler : : ReceivePacket ( )
{
/* Only allow receiving when we have some buffer free; this value
* can go negative , but eventually it will become positive again . */
2019-04-10 23:07:06 +02:00
if ( this - > receive_limit < = 0 ) return nullptr ;
2010-11-30 21:01:26 +01:00
/* We can receive a packet, so try that and if needed account for
* the amount of received data . */
Packet * p = this - > NetworkTCPSocketHandler : : ReceivePacket ( ) ;
2021-04-18 12:29:34 +02:00
if ( p ! = nullptr ) this - > receive_limit - = p - > Size ( ) ;
2010-11-30 21:01:26 +01:00
return p ;
}
2010-10-15 20:42:52 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : CloseConnection ( NetworkRecvStatus status )
{
assert ( status ! = NETWORK_RECV_STATUS_OKAY ) ;
/*
2010-11-30 14:38:46 +01:00
* Sending a message just before leaving the game calls cs - > SendPackets .
2010-10-15 20:42:52 +02:00
* This might invoke this function , which means that when we close the
2010-11-30 14:38:46 +01:00
* connection after cs - > SendPackets we will close an already closed
2010-10-15 20:42:52 +02:00
* connection . This handles that case gracefully without having to make
* that code any more complex or more aware of the validity of the socket .
*/
2023-06-16 21:54:04 +02:00
if ( this - > IsPendingDeletion ( ) | | this - > sock = = INVALID_SOCKET ) return status ;
2010-10-15 20:42:52 +02:00
2021-05-11 12:26:16 +02:00
if ( status ! = NETWORK_RECV_STATUS_CLIENT_QUIT & & status ! = NETWORK_RECV_STATUS_SERVER_ERROR & & ! this - > HasClientQuit ( ) & & this - > status > = STATUS_AUTHORIZED ) {
2010-10-15 20:42:52 +02:00
/* We did not receive a leave message from this client... */
2021-06-14 16:09:50 +02:00
std : : string client_name = this - > GetClientName ( ) ;
2010-10-15 20:42:52 +02:00
2021-05-14 18:12:37 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " " , STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST ) ;
2010-10-15 20:42:52 +02:00
/* Inform other clients of this... strange leaving ;) */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2010-10-15 20:42:52 +02:00
if ( new_cs - > status > STATUS_AUTHORIZED & & this ! = new_cs ) {
2010-10-15 22:25:07 +02:00
new_cs - > SendErrorQuit ( this - > client_id , NETWORK_ERROR_CONNECTION_LOST ) ;
2010-10-15 20:42:52 +02:00
}
}
}
2021-02-27 10:50:41 +01:00
/* If we were transfering a map to this client, stop the savegame creation
* process and queue the next client to receive the map . */
if ( this - > status = = STATUS_MAP ) {
/* Ensure the saving of the game is stopped too. */
this - > savegame - > Destroy ( ) ;
this - > savegame = nullptr ;
this - > CheckNextClientToSendMap ( this ) ;
}
2011-04-30 14:09:26 +02:00
NetworkAdminClientError ( this - > client_id , NETWORK_ERROR_CONNECTION_LOST ) ;
2021-09-19 22:52:46 +02:00
Debug ( net , 3 , " [{}] Client #{} closed connection " , ServerNetworkGameSocketHandler : : GetName ( ) , this - > client_id ) ;
2010-10-15 20:42:52 +02:00
/* We just lost one client :( */
if ( this - > status > = STATUS_AUTHORIZED ) _network_game_info . clients_on - - ;
extern byte _network_clients_connected ;
_network_clients_connected - - ;
2010-11-30 14:38:46 +01:00
this - > SendPackets ( true ) ;
2010-10-15 20:42:52 +02:00
2023-06-16 21:54:04 +02:00
this - > DeferDeletion ( ) ;
2010-10-15 20:42:52 +02:00
2021-04-18 09:54:47 +02:00
InvalidateWindowData ( WC_CLIENT_LIST , 0 ) ;
2010-10-15 20:42:52 +02:00
return status ;
}
2010-10-15 15:22:00 +02:00
2010-10-15 23:56:06 +02:00
/**
* Whether an connection is allowed or not at this moment .
* @ return true if the connection is allowed .
*/
/* static */ bool ServerNetworkGameSocketHandler : : AllowConnection ( )
{
extern byte _network_clients_connected ;
2021-08-23 19:38:02 +02:00
bool accept = _network_clients_connected < MAX_CLIENTS ;
2011-02-08 22:47:10 +01:00
/* We can't go over the MAX_CLIENTS limit here. However, the
* pool must have place for all clients and ourself . */
2020-12-27 11:44:22 +01:00
static_assert ( NetworkClientSocketPool : : MAX_SIZE = = MAX_CLIENTS + 1 ) ;
2011-02-15 14:15:12 +01:00
assert ( ! accept | | ServerNetworkGameSocketHandler : : CanAllocateItem ( ) ) ;
2011-02-08 22:47:10 +01:00
return accept ;
2010-10-15 23:56:06 +02:00
}
/** Send the packets for the server sockets. */
/* static */ void ServerNetworkGameSocketHandler : : Send ( )
{
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-10-15 23:56:06 +02:00
if ( cs - > writable ) {
2011-02-17 19:45:44 +01:00
if ( cs - > SendPackets ( ) ! = SPS_CLOSED & & cs - > status = = STATUS_MAP ) {
2010-10-15 23:56:06 +02:00
/* This client is in the middle of a map-send, call the function for that */
cs - > SendMap ( ) ;
}
}
}
}
2009-01-10 01:31:47 +01:00
static void NetworkHandleCommandQueue ( NetworkClientSocket * cs ) ;
2004-12-19 11:17:26 +01:00
2009-03-15 01:32:18 +01:00
/***********
* Sending functions
* DEF_SERVER_SEND_COMMAND has parameter : NetworkClientSocket * cs
* * * * * * * * * * * */
2004-12-04 18:54:56 +01:00
2011-05-05 18:24:48 +02:00
/**
* Send the client information about a client .
* @ param ci The client to send information about .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendClientInfo ( NetworkClientInfo * ci )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendClientInfo(): client_id={} " , this - > client_id , ci - > client_id ) ;
2008-12-22 13:59:31 +01:00
if ( ci - > client_id ! = INVALID_CLIENT_ID ) {
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_CLIENT_INFO ) ;
2008-12-22 13:59:31 +01:00
p - > Send_uint32 ( ci - > client_id ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( ci - > client_playas ) ;
p - > Send_string ( ci - > client_name ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2004-12-04 18:54:56 +01:00
}
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2021-04-26 20:02:27 +02:00
/** Send the client information about the server. */
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendGameInfo ( )
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendGameInfo() " , this - > client_id ) ;
2021-05-09 19:07:58 +02:00
Packet * p = new Packet ( PACKET_SERVER_GAME_INFO , TCP_MTU ) ;
2021-05-05 19:15:37 +02:00
SerializeNetworkGameInfo ( p , GetCurrentNetworkServerGameInfo ( ) ) ;
2021-04-26 20:02:27 +02:00
this - > SendPacket ( p ) ;
return NETWORK_RECV_STATUS_OKAY ;
}
2011-05-05 18:24:48 +02:00
/**
* Send an error to the client , and close its connection .
* @ param error The error to disconnect for .
2020-01-21 16:39:10 +01:00
* @ param reason In case of kicking a client , specifies the reason for kicking the client .
2011-05-05 18:24:48 +02:00
*/
2021-05-29 19:47:58 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendError ( NetworkErrorCode error , const std : : string & reason )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendError(): error={} " , this - > client_id , error ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_ERROR ) ;
2006-04-02 14:41:01 +02:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( error ) ;
2021-05-29 19:47:58 +02:00
if ( ! reason . empty ( ) ) p - > Send_string ( reason ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2004-12-04 18:54:56 +01:00
2008-12-29 11:37:53 +01:00
StringID strid = GetNetworkErrorMsg ( error ) ;
2006-01-25 19:11:06 +01:00
2009-03-15 01:32:18 +01:00
/* Only send when the current client was in game */
2010-10-15 22:25:07 +02:00
if ( this - > status > STATUS_AUTHORIZED ) {
2021-06-14 16:09:50 +02:00
std : : string client_name = this - > GetClientName ( ) ;
2004-12-04 18:54:56 +01:00
2021-06-12 09:10:17 +02:00
Debug ( net , 1 , " '{}' made an error and has been disconnected: {} " , client_name , GetString ( strid ) ) ;
2004-12-04 18:54:56 +01:00
2021-05-29 19:47:58 +02:00
if ( error = = NETWORK_ERROR_KICKED & & ! reason . empty ( ) ) {
2020-01-21 16:39:10 +01:00
NetworkTextMessage ( NETWORK_ACTION_KICKED , CC_DEFAULT , false , client_name , reason , strid ) ;
} else {
2021-05-14 18:12:37 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " " , strid ) ;
2020-01-21 16:39:10 +01:00
}
2004-12-04 18:54:56 +01:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( new_cs - > status > = STATUS_AUTHORIZED & & new_cs ! = this ) {
2009-03-15 01:32:18 +01:00
/* Some errors we filter to a more general error. Clients don't have to know the real
* reason a joining failed . */
2010-07-24 12:14:39 +02:00
if ( error = = NETWORK_ERROR_NOT_AUTHORIZED | | error = = NETWORK_ERROR_NOT_EXPECTED | | error = = NETWORK_ERROR_WRONG_REVISION ) {
2004-12-04 18:54:56 +01:00
error = NETWORK_ERROR_ILLEGAL_PACKET ;
2010-07-24 12:14:39 +02:00
}
2010-10-15 22:25:07 +02:00
new_cs - > SendErrorQuit ( this - > client_id , error ) ;
2004-12-04 18:54:56 +01:00
}
}
2010-10-17 19:37:26 +02:00
NetworkAdminClientError ( this - > client_id , error ) ;
2004-12-04 18:54:56 +01:00
} else {
2021-06-12 09:10:17 +02:00
Debug ( net , 1 , " Client {} made an error and has been disconnected: {} " , this - > client_id , GetString ( strid ) ) ;
2004-12-04 18:54:56 +01:00
}
2021-05-09 19:02:17 +02:00
/* The client made a mistake, so drop the connection now! */
2010-10-15 22:25:07 +02:00
return this - > CloseConnection ( NETWORK_RECV_STATUS_SERVER_ERROR ) ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Send the check for the NewGRFs. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendNewGRFCheck ( )
2007-01-30 18:22:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendNewGRFCheck() " , this - > client_id ) ;
2021-05-09 19:07:58 +02:00
Packet * p = new Packet ( PACKET_SERVER_CHECK_NEWGRFS , TCP_MTU ) ;
2007-01-30 18:22:56 +01:00
const GRFConfig * c ;
uint grf_count = 0 ;
2019-04-10 23:07:06 +02:00
for ( c = _grfconfig ; c ! = nullptr ; c = c - > next ) {
2007-11-19 22:02:30 +01:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) grf_count + + ;
2007-07-03 18:14:29 +02:00
}
2007-01-30 18:22:56 +01:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( grf_count ) ;
2019-04-10 23:07:06 +02:00
for ( c = _grfconfig ; c ! = nullptr ; c = c - > next ) {
2021-04-26 15:18:10 +02:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) SerializeGRFIdentifier ( p , & c - > ident ) ;
2007-01-30 18:22:56 +01:00
}
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2007-01-30 18:22:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Request the game password. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendNeedGamePassword ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendNeedGamePassword() " , this - > client_id ) ;
2010-04-11 19:17:12 +02:00
/* Invalid packet when status is STATUS_AUTH_GAME or higher */
2010-10-15 22:25:07 +02:00
if ( this - > status > = STATUS_AUTH_GAME ) return this - > CloseConnection ( NETWORK_RECV_STATUS_MALFORMED_PACKET ) ;
2010-04-11 19:17:12 +02:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = AUTH_GAME " , this - > client_id ) ;
2010-10-15 22:25:07 +02:00
this - > status = STATUS_AUTH_GAME ;
2012-05-09 21:14:36 +02:00
/* Reset 'lag' counters */
this - > last_frame = this - > last_frame_server = _frame_counter ;
2010-04-11 19:17:12 +02:00
Packet * p = new Packet ( PACKET_SERVER_NEED_GAME_PASSWORD ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-04-11 19:17:12 +02:00
return NETWORK_RECV_STATUS_OKAY ;
}
2011-05-05 18:24:48 +02:00
/** Request the company password. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendNeedCompanyPassword ( )
2010-04-11 19:17:12 +02:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendNeedCompanyPassword() " , this - > client_id ) ;
2010-04-11 19:17:12 +02:00
/* Invalid packet when status is STATUS_AUTH_COMPANY or higher */
2010-10-15 22:25:07 +02:00
if ( this - > status > = STATUS_AUTH_COMPANY ) return this - > CloseConnection ( NETWORK_RECV_STATUS_MALFORMED_PACKET ) ;
2007-03-06 23:00:42 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = AUTH_COMPANY " , this - > client_id ) ;
2010-10-15 22:25:07 +02:00
this - > status = STATUS_AUTH_COMPANY ;
2012-05-09 21:14:36 +02:00
/* Reset 'lag' counters */
this - > last_frame = this - > last_frame_server = _frame_counter ;
2007-03-06 23:00:42 +01:00
2010-04-11 19:17:12 +02:00
Packet * p = new Packet ( PACKET_SERVER_NEED_COMPANY_PASSWORD ) ;
2008-05-29 17:13:28 +02:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 22:21:28 +02:00
p - > Send_string ( _settings_client . network . network_id ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Send the client a welcome message with some basic information. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendWelcome ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendWelcome() " , this - > client_id ) ;
2004-12-04 18:54:56 +01:00
Packet * p ;
2009-03-15 01:32:18 +01:00
/* Invalid packet when status is AUTH or higher */
2010-10-15 22:25:07 +02:00
if ( this - > status > = STATUS_AUTHORIZED ) return this - > CloseConnection ( NETWORK_RECV_STATUS_MALFORMED_PACKET ) ;
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = AUTHORIZED " , this - > client_id ) ;
2010-10-15 22:25:07 +02:00
this - > status = STATUS_AUTHORIZED ;
2012-05-09 21:14:36 +02:00
/* Reset 'lag' counters */
this - > last_frame = this - > last_frame_server = _frame_counter ;
2004-12-04 18:54:56 +01:00
_network_game_info . clients_on + + ;
2009-10-09 13:03:00 +02:00
p = new Packet ( PACKET_SERVER_WELCOME ) ;
2010-10-15 22:25:07 +02:00
p - > Send_uint32 ( this - > client_id ) ;
2008-05-29 17:13:28 +02:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 22:21:28 +02:00
p - > Send_string ( _settings_client . network . network_id ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2004-12-04 18:54:56 +01:00
2010-10-24 17:02:43 +02:00
/* Transmit info about all the active clients */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( new_cs ! = this & & new_cs - > status > = STATUS_AUTHORIZED ) {
2010-10-15 22:25:07 +02:00
this - > SendClientInfo ( new_cs - > GetInfo ( ) ) ;
2010-07-24 12:14:39 +02:00
}
2004-12-04 18:54:56 +01:00
}
2009-03-15 01:32:18 +01:00
/* Also send the info of the server */
2011-04-22 17:54:16 +02:00
return this - > SendClientInfo ( NetworkClientInfo : : GetByClientID ( CLIENT_ID_SERVER ) ) ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Tell the client that its put in a waiting queue. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendWait ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendWait() " , this - > client_id ) ;
2021-02-27 10:29:29 +01:00
int waiting = 1 ; // current player getting the map counts as 1
2004-12-04 18:54:56 +01:00
Packet * p ;
2011-04-22 18:07:47 +02:00
/* Count how many clients are waiting in the queue, in front of you! */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2011-04-22 18:07:47 +02:00
if ( new_cs - > status ! = STATUS_MAP_WAIT ) continue ;
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 + + ;
2004-12-04 18:54:56 +01:00
}
2009-10-09 13:03:00 +02:00
p = new Packet ( PACKET_SERVER_WAIT ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( waiting ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2021-02-27 10:50:41 +01:00
void ServerNetworkGameSocketHandler : : CheckNextClientToSendMap ( NetworkClientSocket * ignore_cs )
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] CheckNextClientToSendMap() " , this - > client_id ) ;
2021-02-27 10:50:41 +01:00
/* Find the best candidate for joining, i.e. the first joiner. */
NetworkClientSocket * best = nullptr ;
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
if ( ignore_cs = = new_cs ) continue ;
if ( new_cs - > status = = STATUS_MAP_WAIT ) {
if ( best = = nullptr | | best - > GetInfo ( ) - > join_date > new_cs - > GetInfo ( ) - > join_date | | ( best - > GetInfo ( ) - > join_date = = new_cs - > GetInfo ( ) - > join_date & & best - > client_id > new_cs - > client_id ) ) {
best = new_cs ;
}
}
}
/* Is there someone else to join? */
if ( best ! = nullptr ) {
/* Let the first start joining. */
best - > status = STATUS_AUTHORIZED ;
best - > SendMap ( ) ;
/* And update the rest. */
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
if ( new_cs - > status = = STATUS_MAP_WAIT ) new_cs - > SendWait ( ) ;
}
}
}
2011-05-05 18:24:48 +02:00
/** This sends the map to the client */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendMap ( )
2004-12-04 18:54:56 +01:00
{
2010-10-15 22:25:07 +02:00
if ( this - > status < STATUS_AUTHORIZED ) {
2009-03-15 01:32:18 +01:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_AUTHORIZED ) ;
2004-12-04 18:54:56 +01:00
}
2006-10-18 01:34:12 +02:00
2010-10-15 22:25:07 +02:00
if ( this - > status = = STATUS_AUTHORIZED ) {
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendMap(): first_packet " , this - > client_id ) ;
2023-05-21 19:53:21 +02:00
WaitTillSaved ( ) ;
2010-12-05 15:45:52 +01:00
this - > savegame = new PacketWriter ( this ) ;
2007-01-17 01:01:55 +01:00
2009-03-15 01:32:18 +01:00
/* Now send the _frame_counter and how many packets are coming */
2010-11-26 23:25:02 +01:00
Packet * p = new Packet ( PACKET_SERVER_MAP_BEGIN ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _frame_counter ) ;
2010-12-05 15:34:19 +01:00
this - > SendPacket ( p ) ;
2010-10-15 22:25:07 +02:00
NetworkSyncCommandQueue ( this ) ;
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = MAP " , this - > client_id ) ;
2010-10-15 22:25:07 +02:00
this - > status = STATUS_MAP ;
2005-03-29 21:10:13 +02:00
/* Mark the start of download */
2010-10-15 22:25:07 +02:00
this - > last_frame = _frame_counter ;
this - > last_frame_server = _frame_counter ;
2010-12-05 15:45:52 +01:00
/* Make a dump of the current game */
2023-04-19 22:47:36 +02:00
if ( SaveWithFilter ( this - > savegame , true ) ! = SL_OK ) UserError ( " network savedump failed " ) ;
2004-12-04 18:54:56 +01:00
}
2010-10-15 22:25:07 +02:00
if ( this - > status = = STATUS_MAP ) {
2021-04-25 19:59:19 +02:00
bool last_packet = this - > savegame - > TransferToNetworkQueue ( this ) ;
2011-04-09 23:52:38 +02:00
if ( last_packet ) {
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendMap(): last_packet " , this - > client_id ) ;
2011-04-09 23:52:38 +02:00
/* Done reading, make sure saving is done as well */
2013-11-15 23:22:01 +01:00
this - > savegame - > Destroy ( ) ;
2019-04-10 23:07:06 +02:00
this - > savegame = nullptr ;
2013-11-15 23:22:01 +01:00
2011-04-09 23:52:38 +02:00
/* Set the status to DONE_MAP, no we will wait for the client
2011-04-17 15:36:51 +02:00
* to send it is ready ( maybe that happens like never ; ) ) */
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = DONE_MAP " , this - > client_id ) ;
2011-04-09 23:52:38 +02:00
this - > status = STATUS_DONE_MAP ;
2021-02-27 10:50:41 +01:00
this - > CheckNextClientToSendMap ( ) ;
2011-04-09 23:52:38 +02:00
}
2004-12-04 18:54:56 +01:00
}
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Tell that a client joined .
* @ param client_id The client that joined .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendJoin ( ClientID client_id )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendJoin(): client_id={} " , this - > client_id , client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_JOIN ) ;
2004-12-04 18:54:56 +01:00
2008-12-22 13:59:31 +01:00
p - > Send_uint32 ( client_id ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Tell the client that they may run to a particular frame. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendFrame ( )
2004-12-04 18:54:56 +01:00
{
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_FRAME ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _frame_counter_max ) ;
2004-12-04 18:54:56 +01:00
# ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 18:54:56 +01:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 18:54:56 +01:00
# endif
# endif
2010-11-30 15:18:20 +01:00
/* If token equals 0, we need to make a new token and send that. */
if ( this - > last_token = = 0 ) {
this - > last_token = InteractiveRandomRange ( UINT8_MAX - 1 ) + 1 ;
p - > Send_uint8 ( this - > last_token ) ;
}
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Request the client to sync. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendSync ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendSync(), frame_counter={}, sync_seed_1={} " , this - > client_id , _frame_counter , _sync_seed_1 ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_SYNC ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 18:54:56 +01:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 18:54:56 +01:00
# endif
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Send a command to the client to execute .
* @ param cp The command to send .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendCommand ( const CommandPacket * cp )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendCommand(): cmd={} " , this - > client_id , cp - > cmd ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_COMMAND ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > NetworkGameSocketHandler : : SendCommand ( p , cp ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( cp - > frame ) ;
2007-07-10 22:59:41 +02:00
p - > Send_bool ( cp - > my_cmd ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Send a chat message .
* @ param action The action associated with the message .
* @ param client_id The origin of the chat message .
* @ param self_send Whether we did send the message .
* @ param msg The actual message .
* @ param data Arbitrary extra data .
*/
2023-05-08 19:01:06 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendChat ( NetworkAction action , ClientID client_id , bool self_send , const std : : string & msg , int64_t data )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendChat(): action={}, client_id={}, self_send={} " , this - > client_id , action , client_id , self_send ) ;
2012-02-16 21:44:03 +01:00
if ( this - > status < STATUS_PRE_ACTIVE ) return NETWORK_RECV_STATUS_OKAY ;
2011-11-26 18:28:18 +01:00
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_CHAT ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( action ) ;
2008-12-22 13:59:31 +01:00
p - > Send_uint32 ( client_id ) ;
2007-02-03 00:16:58 +01:00
p - > Send_bool ( self_send ) ;
2007-02-02 00:26:44 +01:00
p - > Send_string ( msg ) ;
2008-12-29 11:37:53 +01:00
p - > Send_uint64 ( data ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2021-09-19 23:09:06 +02:00
/**
* Send a chat message from external source .
* @ param source Name of the source this message came from .
* @ param colour TextColour to use for the message .
* @ param user Name of the user who sent the messsage .
* @ param msg The actual message .
*/
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendExternalChat ( const std : : string & source , TextColour colour , const std : : string & user , const std : : string & msg )
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendExternalChat(): source={} " , this - > client_id , source ) ;
2021-09-19 23:09:06 +02:00
if ( this - > status < STATUS_PRE_ACTIVE ) return NETWORK_RECV_STATUS_OKAY ;
Packet * p = new Packet ( PACKET_SERVER_EXTERNAL_CHAT ) ;
p - > Send_string ( source ) ;
p - > Send_uint16 ( colour ) ;
p - > Send_string ( user ) ;
p - > Send_string ( msg ) ;
this - > SendPacket ( p ) ;
return NETWORK_RECV_STATUS_OKAY ;
}
2011-05-05 18:24:48 +02:00
/**
* Tell the client another client quit with an error .
* @ param client_id The client that quit .
* @ param errorno The reason the client quit .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendErrorQuit ( ClientID client_id , NetworkErrorCode errorno )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendErrorQuit(): client_id={}, errorno={} " , this - > client_id , client_id , errorno ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_ERROR_QUIT ) ;
2004-12-04 18:54:56 +01:00
2008-12-22 13:59:31 +01:00
p - > Send_uint32 ( client_id ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( errorno ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Tell the client another client quit .
* @ param client_id The client that quit .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendQuit ( ClientID client_id )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendQuit(): client_id={} " , this - > client_id , client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_QUIT ) ;
2004-12-04 18:54:56 +01:00
2008-12-22 13:59:31 +01:00
p - > Send_uint32 ( client_id ) ;
2004-12-04 18:54:56 +01:00
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Tell the client we're shutting down. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendShutdown ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendShutdown() " , this - > client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_SHUTDOWN ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** Tell the client we're starting a new game. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendNewGame ( )
2004-12-04 18:54:56 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendNewGame() " , this - > client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_NEWGAME ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Send the result of a console action .
* @ param colour The colour of the result .
* @ param command The command that was executed .
*/
2023-05-08 19:01:06 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendRConResult ( uint16_t colour , const std : : string & command )
2005-01-15 21:09:16 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendRConResult() " , this - > client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_RCON ) ;
2005-01-15 21:09:16 +01:00
2009-02-09 03:57:15 +01:00
p - > Send_uint16 ( colour ) ;
2007-02-02 00:26:44 +01:00
p - > Send_string ( command ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2005-01-15 21:09:16 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Tell that a client moved to another company .
* @ param client_id The client that moved .
* @ param company_id The company the client moved to .
*/
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendMove ( ClientID client_id , CompanyID company_id )
2009-01-23 23:18:06 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendMove(): client_id={} " , this - > client_id , client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_MOVE ) ;
2009-01-23 23:18:06 +01:00
p - > Send_uint32 ( client_id ) ;
p - > Send_uint8 ( company_id ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
2011-05-05 18:24:48 +02:00
/** Send an update about the company password states. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendCompanyUpdate ( )
2009-01-23 23:18:06 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendCompanyUpdate() " , this - > client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_COMPANY_UPDATE ) ;
2009-01-23 23:18:06 +01:00
2023-05-08 19:01:06 +02:00
static_assert ( sizeof ( _network_company_passworded ) < = sizeof ( uint16_t ) ) ;
2009-01-23 23:18:06 +01:00
p - > Send_uint16 ( _network_company_passworded ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
2011-05-05 18:24:48 +02:00
/** Send an update about the max company/spectator counts. */
2010-10-15 22:25:07 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : SendConfigUpdate ( )
2009-01-23 23:18:06 +01:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] SendConfigUpdate() " , this - > client_id ) ;
2009-10-09 13:03:00 +02:00
Packet * p = new Packet ( PACKET_SERVER_CONFIG_UPDATE ) ;
2009-01-23 23:18:06 +01:00
p - > Send_uint8 ( _settings_client . network . max_companies ) ;
2021-08-14 10:19:40 +02:00
p - > Send_string ( _settings_client . network . server_name ) ;
2010-11-30 14:38:46 +01:00
this - > SendPacket ( p ) ;
2010-02-10 00:49:19 +01:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
2009-03-15 01:32:18 +01:00
/***********
* Receiving functions
* DEF_SERVER_RECEIVE_COMMAND has parameter : NetworkClientSocket * cs , Packet * p
* * * * * * * * * * * */
2004-12-04 18:54:56 +01:00
2023-09-16 22:20:53 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_GAME_INFO ( Packet * )
2021-04-26 20:02:27 +02:00
{
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_GAME_INFO() " , this - > client_id ) ;
2021-04-26 20:02:27 +02:00
return this - > SendGameInfo ( ) ;
}
2023-09-16 22:20:53 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_NEWGRFS_CHECKED ( Packet * )
2007-01-30 18:22:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_NEWGRFS_CHECK ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2008-06-08 10:44:19 +02:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_NEWGRFS_CHECKED() " , this - > client_id ) ;
2010-10-15 15:47:37 +02:00
NetworkClientInfo * ci = this - > GetInfo ( ) ;
2007-01-30 18:22:56 +01:00
2021-05-09 19:02:17 +02:00
/* We now want a password from the client else we do not allow them in! */
2021-04-27 20:26:56 +02:00
if ( ! _settings_client . network . server_password . empty ( ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendNeedGamePassword ( ) ;
2007-01-30 18:22:56 +01:00
}
2010-02-10 00:49:19 +01:00
2021-05-02 08:27:06 +02:00
if ( Company : : IsValidID ( ci - > client_playas ) & & ! _network_company_states [ ci - > client_playas ] . password . empty ( ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendNeedCompanyPassword ( ) ;
2010-02-10 00:49:19 +01:00
}
2010-10-15 22:25:07 +02:00
return this - > SendWelcome ( ) ;
2007-01-30 18:22:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_JOIN ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_INACTIVE ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2008-06-08 10:44:19 +02:00
}
2021-08-23 19:38:02 +02:00
if ( _network_game_info . clients_on > = _settings_client . network . max_clients ) {
/* Turns out we are full. Inform the user about this. */
return this - > SendError ( NETWORK_ERROR_FULL ) ;
}
2021-05-30 13:36:07 +02:00
std : : string client_revision = p - > Recv_string ( NETWORK_REVISION_LENGTH ) ;
2023-05-08 19:01:06 +02:00
uint32_t newgrf_version = p - > Recv_uint32 ( ) ;
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_JOIN(): client_revision={}, newgrf_version={} " , this - > client_id , client_revision , newgrf_version ) ;
2009-03-15 01:32:18 +01:00
/* Check if the client has revision control enabled */
2021-06-13 23:41:15 +02:00
if ( ! IsNetworkCompatibleVersion ( client_revision ) | | _openttd_newgrf_version ! = newgrf_version ) {
2009-03-15 01:32:18 +01:00
/* Different revisions!! */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_WRONG_REVISION ) ;
2004-12-04 18:54:56 +01:00
}
2021-05-29 20:22:41 +02:00
std : : string client_name = p - > Recv_string ( NETWORK_CLIENT_NAME_LENGTH ) ;
CompanyID playas = ( Owner ) p - > Recv_uint8 ( ) ;
2005-01-05 15:39:48 +01:00
2021-05-11 12:26:16 +02:00
if ( this - > HasClientQuit ( ) ) return NETWORK_RECV_STATUS_CLIENT_QUIT ;
2004-12-04 18:54:56 +01:00
2009-03-15 01:32:18 +01:00
/* join another company does not affect these values */
2006-01-25 19:11:06 +01:00
switch ( playas ) {
2009-03-15 01:32:18 +01:00
case COMPANY_NEW_COMPANY : // New company
2009-05-22 17:23:47 +02:00
if ( Company : : GetNumItems ( ) > = _settings_client . network . max_companies ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_FULL ) ;
2006-01-25 19:11:06 +01:00
}
break ;
2009-03-15 01:32:18 +01:00
case COMPANY_SPECTATOR : // Spectator
2006-01-25 19:11:06 +01:00
break ;
2009-03-15 01:32:18 +01:00
default : // Join another company (companies 1-8 (index 0-7))
2009-06-11 00:05:01 +02:00
if ( ! Company : : IsValidHumanID ( playas ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_COMPANY_MISMATCH ) ;
2006-10-16 01:48:34 +02:00
}
break ;
2004-12-04 18:54:56 +01:00
}
2021-05-29 20:22:41 +02:00
if ( ! NetworkIsValidClientName ( client_name ) ) {
2021-04-22 08:17:36 +02:00
/* An invalid client name was given. However, the client ensures the name
* is valid before it is sent over the network , so something went horribly
* wrong . This is probably someone trying to troll us . */
return this - > SendError ( NETWORK_ERROR_INVALID_CLIENT_NAME ) ;
}
2006-01-25 19:11:06 +01:00
2021-05-29 20:22:41 +02:00
if ( ! NetworkMakeClientNameUnique ( client_name ) ) { // Change name if duplicate
2009-03-15 01:32:18 +01:00
/* We could not create a name for this client */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NAME_IN_USE ) ;
2004-12-04 18:54:56 +01:00
}
2011-04-22 18:05:05 +02:00
assert ( NetworkClientInfo : : CanAllocateItem ( ) ) ;
NetworkClientInfo * ci = new NetworkClientInfo ( this - > client_id ) ;
this - > SetInfo ( ci ) ;
2024-01-22 15:04:34 +01:00
ci - > join_date = TimerGameEconomy : : date ;
2021-05-29 20:22:41 +02:00
ci - > client_name = client_name ;
2004-12-04 18:54:56 +01:00
ci - > client_playas = playas ;
2024-01-22 15:04:34 +01:00
Debug ( desync , 1 , " client: {:08x}; {:02x}; {:02x}; {:02x} " , TimerGameEconomy : : date , TimerGameEconomy : : date_fract , ( int ) ci - > client_playas , ( int ) ci - > index ) ;
2004-12-04 18:54:56 +01:00
2006-10-18 00:16:46 +02:00
/* Make sure companies to which people try to join are not autocleaned */
2009-05-17 03:00:56 +02:00
if ( Company : : IsValidID ( playas ) ) _network_company_states [ playas ] . months_empty = 0 ;
2007-01-30 18:22:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = NEWGRFS_CHECK " , this - > client_id ) ;
2010-10-15 15:47:37 +02:00
this - > status = STATUS_NEWGRFS_CHECK ;
2010-04-22 19:26:57 +02:00
2019-04-10 23:07:06 +02:00
if ( _grfconfig = = nullptr ) {
2010-04-22 19:26:57 +02:00
/* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */
2019-04-10 23:07:06 +02:00
return this - > Receive_CLIENT_NEWGRFS_CHECKED ( nullptr ) ;
2007-01-30 18:22:56 +01:00
}
2010-02-10 00:49:19 +01:00
2010-10-15 22:25:07 +02:00
return this - > SendNewGRFCheck ( ) ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_GAME_PASSWORD ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_AUTH_GAME ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2010-04-11 19:17:12 +02:00
}
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_GAME_PASSWORD() " , this - > client_id ) ;
2021-05-02 09:10:09 +02:00
std : : string password = p - > Recv_string ( NETWORK_PASSWORD_LENGTH ) ;
2004-12-04 18:54:56 +01:00
2010-04-11 19:23:11 +02:00
/* Check game password. Allow joining if we cleared the password meanwhile */
2021-04-27 20:26:56 +02:00
if ( ! _settings_client . network . server_password . empty ( ) & &
_settings_client . network . server_password . compare ( password ) ! = 0 ) {
2010-04-11 19:17:12 +02:00
/* Password is invalid */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_WRONG_PASSWORD ) ;
2010-04-11 19:17:12 +02:00
}
2004-12-04 18:54:56 +01:00
2010-10-15 15:47:37 +02:00
const NetworkClientInfo * ci = this - > GetInfo ( ) ;
2021-05-02 08:27:06 +02:00
if ( Company : : IsValidID ( ci - > client_playas ) & & ! _network_company_states [ ci - > client_playas ] . password . empty ( ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendNeedCompanyPassword ( ) ;
2010-04-11 19:17:12 +02:00
}
2004-12-04 18:54:56 +01:00
2010-04-11 19:17:12 +02:00
/* Valid password, allow user */
2010-10-15 22:25:07 +02:00
return this - > SendWelcome ( ) ;
2010-04-11 19:17:12 +02:00
}
2004-12-04 18:54:56 +01:00
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_COMPANY_PASSWORD ( Packet * p )
2010-04-11 19:17:12 +02:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_AUTH_COMPANY ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2010-04-11 19:17:12 +02:00
}
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_COMPANY_PASSWORD() " , this - > client_id ) ;
2021-05-02 09:07:09 +02:00
std : : string password = p - > Recv_string ( NETWORK_PASSWORD_LENGTH ) ;
2004-12-04 18:54:56 +01:00
2010-04-12 00:06:17 +02:00
/* 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 */
2010-10-15 15:47:37 +02:00
CompanyID playas = this - > GetInfo ( ) - > client_playas ;
2021-05-02 08:27:06 +02:00
if ( Company : : IsValidID ( playas ) & & ! _network_company_states [ playas ] . password . empty ( ) & &
_network_company_states [ playas ] . password . compare ( password ) ! = 0 ) {
2010-04-11 19:17:12 +02:00
/* Password is invalid */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_WRONG_PASSWORD ) ;
2004-12-04 18:54:56 +01:00
}
2010-10-15 22:25:07 +02:00
return this - > SendWelcome ( ) ;
2004-12-04 18:54:56 +01:00
}
2023-09-16 22:20:53 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_GETMAP ( Packet * )
2004-12-04 18:54:56 +01:00
{
2009-03-15 01:32:18 +01:00
/* The client was never joined.. so this is impossible, right?
2021-05-09 19:02:17 +02:00
* Ignore the packet , give the client a warning , and close the connection */
2010-10-15 15:47:37 +02:00
if ( this - > status < STATUS_AUTHORIZED | | this - > HasClientQuit ( ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_AUTHORIZED ) ;
2004-12-04 18:54:56 +01:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_GETMAP() " , this - > client_id ) ;
2009-03-15 01:32:18 +01:00
/* Check if someone else is receiving the map */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2004-12-04 18:54:56 +01:00
if ( new_cs - > status = = STATUS_MAP ) {
2009-03-15 01:32:18 +01:00
/* Tell the new client to wait */
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = MAP_WAIT " , this - > client_id ) ;
2010-10-15 15:47:37 +02:00
this - > status = STATUS_MAP_WAIT ;
2010-10-15 22:25:07 +02:00
return this - > SendWait ( ) ;
2004-12-04 18:54:56 +01:00
}
}
2009-03-15 01:32:18 +01:00
/* We receive a request to upload the map.. give it to the client! */
2010-10-15 22:25:07 +02:00
return this - > SendMap ( ) ;
2004-12-04 18:54:56 +01:00
}
2023-09-16 22:20:53 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_MAP_OK ( Packet * )
2004-12-04 18:54:56 +01:00
{
2009-03-15 01:32:18 +01:00
/* Client has the map, now start syncing */
2010-10-15 15:47:37 +02:00
if ( this - > status = = STATUS_DONE_MAP & & ! this - > HasClientQuit ( ) ) {
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_MAP_OK() " , this - > client_id ) ;
2021-06-14 16:09:50 +02:00
std : : string client_name = this - > GetClientName ( ) ;
2004-12-04 18:54:56 +01:00
2021-05-14 18:12:37 +02:00
NetworkTextMessage ( NETWORK_ACTION_JOIN , CC_DEFAULT , false , client_name , " " , this - > client_id ) ;
2021-04-18 09:54:47 +02:00
InvalidateWindowData ( WC_CLIENT_LIST , 0 ) ;
2004-12-04 18:54:56 +01:00
2021-09-19 22:52:46 +02:00
Debug ( net , 3 , " [{}] Client #{} ({}) joined as {} " , ServerNetworkGameSocketHandler : : GetName ( ) , this - > client_id , this - > GetClientIP ( ) , client_name ) ;
2009-03-15 01:32:18 +01:00
/* Mark the client as pre-active, and wait for an ACK
2021-05-08 12:02:30 +02:00
* so we know it is done loading and in sync with us */
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = PRE_ACTIVE " , this - > client_id ) ;
2010-10-15 15:47:37 +02:00
this - > status = STATUS_PRE_ACTIVE ;
NetworkHandleCommandQueue ( this ) ;
2010-10-15 22:25:07 +02:00
this - > SendFrame ( ) ;
this - > SendSync ( ) ;
2004-12-04 18:54:56 +01:00
2009-03-15 01:32:18 +01:00
/* This is the frame the client receives
* we need it later on to make sure the client is not too slow */
2010-10-15 15:47:37 +02:00
this - > last_frame = _frame_counter ;
this - > last_frame_server = _frame_counter ;
2004-12-04 18:54:56 +01:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( new_cs - > status > = STATUS_AUTHORIZED ) {
2010-10-15 22:25:07 +02:00
new_cs - > SendClientInfo ( this - > GetInfo ( ) ) ;
new_cs - > SendJoin ( this - > client_id ) ;
2004-12-04 18:54:56 +01:00
}
}
2005-03-29 21:10:13 +02:00
2011-04-22 18:03:13 +02:00
NetworkAdminClientInfo ( this , true ) ;
2010-10-17 19:37:26 +02:00
2009-01-23 23:18:06 +01:00
/* also update the new client with our max values */
2010-10-15 22:25:07 +02:00
this - > SendConfigUpdate ( ) ;
2009-01-23 23:18:06 +01:00
/* quickly update the syncing client with company details */
2010-10-15 22:25:07 +02:00
return this - > SendCompanyUpdate ( ) ;
2004-12-04 18:54:56 +01:00
}
2010-02-10 00:49:19 +01:00
/* Wrong status for this packet, give a warning to client, and close connection */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2004-12-04 18:54:56 +01:00
}
2010-08-01 21:22:34 +02:00
/**
* The client has done a command and wants us to handle it
2010-10-15 15:47:37 +02:00
* @ param p the packet in which the command was sent
2005-05-14 21:25:18 +02:00
*/
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_COMMAND ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2009-03-15 01:32:18 +01:00
/* The client was never joined.. so this is impossible, right?
2021-05-09 19:02:17 +02:00
* Ignore the packet , give the client a warning , and close the connection */
2010-10-15 15:47:37 +02:00
if ( this - > status < STATUS_DONE_MAP | | this - > HasClientQuit ( ) ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2004-12-04 18:54:56 +01:00
}
2010-10-15 15:47:37 +02:00
if ( this - > incoming_queue . Count ( ) > = _settings_client . network . max_commands_in_queue ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_TOO_MANY_COMMANDS ) ;
2010-08-19 10:59:36 +02:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_COMMAND() " , this - > client_id ) ;
2009-01-08 14:57:50 +01:00
CommandPacket cp ;
2010-11-30 14:38:46 +01:00
const char * err = this - > ReceiveCommand ( p , & cp ) ;
2005-01-05 15:39:48 +01:00
2021-05-11 12:26:16 +02:00
if ( this - > HasClientQuit ( ) ) return NETWORK_RECV_STATUS_CLIENT_QUIT ;
2005-05-14 21:25:18 +02:00
2010-10-15 15:47:37 +02:00
NetworkClientInfo * ci = this - > GetInfo ( ) ;
2005-01-05 15:39:48 +01:00
2019-04-10 23:07:06 +02:00
if ( err ! = nullptr ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Dropping client #{} (IP: {}) due to {}. " , ci - > client_id , this - > GetClientIP ( ) , err ) ;
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2005-01-05 15:39:48 +01:00
}
2004-12-04 18:54:56 +01:00
2009-01-08 15:40:18 +01:00
2009-06-01 13:43:36 +02:00
if ( ( GetCommandFlags ( cp . cmd ) & CMD_SERVER ) & & ci - > client_id ! = CLIENT_ID_SERVER ) {
2021-10-03 21:13:32 +02:00
IConsolePrint ( CC_WARNING , " Kicking client #{} (IP: {}) due to calling a server only command {}. " , ci - > client_id , this - > GetClientIP ( ) , cp . cmd ) ;
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_KICKED ) ;
2009-01-08 15:40:18 +01:00
}
2009-05-17 03:00:56 +02:00
if ( ( GetCommandFlags ( cp . cmd ) & CMD_SPECTATOR ) = = 0 & & ! Company : : IsValidID ( cp . company ) & & ci - > client_id ! = CLIENT_ID_SERVER ) {
2021-10-03 21:13:32 +02:00
IConsolePrint ( CC_WARNING , " Kicking client #{} (IP: {}) due to calling a non-spectator command {}. " , ci - > client_id , this - > GetClientIP ( ) , cp . cmd ) ;
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_KICKED ) ;
2005-05-14 21:25:18 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Only CMD_COMPANY_CTRL is always allowed , for the rest , playas needs
2008-09-30 22:39:50 +02:00
* to match the company in the packet . If it doesn ' t , the client has done
2005-05-14 21:25:18 +02:00
* something pretty naughty ( or a bug ) , and will be kicked
*/
2021-11-02 21:34:39 +01:00
CompanyCtrlAction cca = cp . cmd = = CMD_COMPANY_CTRL ? std : : get < 0 > ( EndianBufferReader : : ToValue < CommandTraits < CMD_COMPANY_CTRL > : : Args > ( cp . data ) ) : CCA_NEW ;
if ( ! ( cp . cmd = = CMD_COMPANY_CTRL & & cca = = CCA_NEW & & ci - > client_playas = = COMPANY_NEW_COMPANY ) & & ci - > client_playas ! = cp . company ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Kicking client #{} (IP: {}) due to calling a command as another company {}. " ,
2011-04-22 18:02:21 +02:00
ci - > client_playas + 1 , this - > GetClientIP ( ) , cp . company + 1 ) ;
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_COMPANY_MISMATCH ) ;
2004-12-04 18:54:56 +01:00
}
2009-01-08 14:57:50 +01:00
if ( cp . cmd = = CMD_COMPANY_CTRL ) {
2021-11-02 21:34:39 +01:00
if ( cca ! = CCA_NEW | | cp . company ! = COMPANY_SPECTATOR ) {
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_CHEATER ) ;
2005-05-14 21:25:18 +02:00
}
2009-01-23 23:18:06 +01:00
/* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */
2009-05-22 17:23:47 +02:00
if ( Company : : GetNumItems ( ) > = _settings_client . network . max_companies ) {
2009-01-23 23:18:06 +01:00
NetworkServerSendChat ( NETWORK_ACTION_SERVER_MESSAGE , DESTTYPE_CLIENT , ci - > client_id , " cannot create new company, server full " , CLIENT_ID_SERVER ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
2005-05-14 21:25:18 +02:00
}
2004-12-04 18:54:56 +01:00
2021-10-28 23:48:26 +02:00
if ( GetCommandFlags ( cp . cmd ) & CMD_CLIENT_ID ) NetworkReplaceCommandClientId ( cp , this - > client_id ) ;
2010-08-18 19:06:45 +02:00
2010-10-15 15:47:37 +02:00
this - > incoming_queue . Append ( & cp ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_ERROR ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2009-03-15 01:32:18 +01:00
/* This packets means a client noticed an error and is reporting this
* to us . Display the error and report it to the other clients */
2007-02-02 00:26:44 +01:00
NetworkErrorCode errorno = ( NetworkErrorCode ) p - > Recv_uint8 ( ) ;
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_ERROR(): errorno={} " , this - > client_id , errorno ) ;
2009-03-15 01:32:18 +01:00
/* The client was never joined.. thank the client for the packet, but ignore it */
2010-10-15 15:47:37 +02:00
if ( this - > status < STATUS_DONE_MAP | | this - > HasClientQuit ( ) ) {
2021-05-11 12:26:16 +02:00
return this - > CloseConnection ( NETWORK_RECV_STATUS_CLIENT_QUIT ) ;
2004-12-04 18:54:56 +01:00
}
2021-06-14 16:09:50 +02:00
std : : string client_name = this - > GetClientName ( ) ;
2008-12-29 11:37:53 +01:00
StringID strid = GetNetworkErrorMsg ( errorno ) ;
2004-12-04 18:54:56 +01:00
2021-06-12 09:10:17 +02:00
Debug ( net , 1 , " '{}' reported an error and is closing its connection: {} " , client_name , GetString ( strid ) ) ;
2004-12-04 18:54:56 +01:00
2021-05-14 18:12:37 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " " , strid ) ;
2004-12-04 18:54:56 +01:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( new_cs - > status > = STATUS_AUTHORIZED ) {
2010-10-20 13:58:34 +02:00
new_cs - > SendErrorQuit ( this - > client_id , errorno ) ;
2004-12-04 18:54:56 +01:00
}
}
2010-10-17 19:37:26 +02:00
NetworkAdminClientError ( this - > client_id , errorno ) ;
2021-05-11 12:26:16 +02:00
return this - > CloseConnection ( NETWORK_RECV_STATUS_CLIENT_QUIT ) ;
2004-12-04 18:54:56 +01:00
}
2023-09-16 22:20:53 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_QUIT ( Packet * )
2004-12-04 18:54:56 +01:00
{
2009-03-15 01:32:18 +01:00
/* The client was never joined.. thank the client for the packet, but ignore it */
2010-10-15 15:47:37 +02:00
if ( this - > status < STATUS_DONE_MAP | | this - > HasClientQuit ( ) ) {
2021-05-11 12:26:16 +02:00
return this - > CloseConnection ( NETWORK_RECV_STATUS_CLIENT_QUIT ) ;
2004-12-04 18:54:56 +01:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_QUIT() " , this - > client_id ) ;
2021-06-14 16:09:50 +02:00
/* The client wants to leave. Display this and report it to the other clients. */
std : : string client_name = this - > GetClientName ( ) ;
2021-05-14 18:12:37 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " " , STR_NETWORK_MESSAGE_CLIENT_LEAVING ) ;
2004-12-04 18:54:56 +01:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * new_cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( new_cs - > status > = STATUS_AUTHORIZED & & new_cs ! = this ) {
2010-10-20 13:58:34 +02:00
new_cs - > SendQuit ( this - > client_id ) ;
2004-12-04 18:54:56 +01:00
}
}
2010-10-17 19:37:26 +02:00
NetworkAdminClientQuit ( this - > client_id ) ;
2021-05-11 12:26:16 +02:00
return this - > CloseConnection ( NETWORK_RECV_STATUS_CLIENT_QUIT ) ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_ACK ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status < STATUS_AUTHORIZED ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_AUTHORIZED ) ;
2008-06-08 10:44:19 +02:00
}
2023-05-08 19:01:06 +02:00
uint32_t frame = p - > Recv_uint32 ( ) ;
2005-03-29 21:10:13 +02:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_ACK(): frame={} " , this - > client_id , frame ) ;
2005-03-29 21:10:13 +02:00
/* The client is trying to catch up with the server */
2010-10-15 15:47:37 +02:00
if ( this - > status = = STATUS_PRE_ACTIVE ) {
2019-09-29 22:27:32 +02:00
/* The client is not yet caught up? */
2023-08-16 15:01:24 +02:00
if ( frame + Ticks : : DAY_TICKS < _frame_counter ) return NETWORK_RECV_STATUS_OKAY ;
2005-03-29 21:10:13 +02:00
2021-05-08 12:02:30 +02:00
/* Now it is! Unpause the game */
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] status = ACTIVE " , this - > client_id ) ;
2010-10-15 15:47:37 +02:00
this - > status = STATUS_ACTIVE ;
2010-11-30 15:18:20 +01:00
this - > last_token_frame = _frame_counter ;
2005-03-29 21:10:13 +02:00
2006-10-03 16:59:05 +02:00
/* Execute script for, e.g. MOTD */
IConsoleCmdExec ( " exec scripts/on_server_connect.scr 0 " ) ;
2005-03-29 21:10:13 +02:00
}
2010-11-30 15:18:20 +01:00
/* Get, and validate the token. */
2023-05-08 19:01:06 +02:00
uint8_t token = p - > Recv_uint8 ( ) ;
2010-11-30 15:18:20 +01:00
if ( token = = this - > last_token ) {
/* We differentiate between last_token_frame and last_frame so the lag
* test uses the actual lag of the client instead of the lag for getting
* the token back and forth ; after all , the token is only sent every
* time we receive a PACKET_CLIENT_ACK , after which we will send a new
* token to the client . If the lag would be one day , then we would not
* be sending the new token soon enough for the new daily scheduled
* PACKET_CLIENT_ACK . This would then register the lag of the client as
* two days , even when it ' s only a single day . */
this - > last_token_frame = _frame_counter ;
/* Request a new token. */
this - > last_token = 0 ;
}
2009-03-15 01:32:18 +01:00
/* The client received the frame, make note of it */
2010-10-15 15:47:37 +02:00
this - > last_frame = frame ;
2009-03-15 01:32:18 +01:00
/* With those 2 values we can calculate the lag realtime */
2010-10-15 15:47:37 +02:00
this - > last_frame_server = _frame_counter ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Send an actual chat message .
* @ param action The action that ' s performed .
* @ param desttype The type of destination .
* @ param dest The actual destination index .
* @ param msg The actual message .
* @ param from_id The origin of the message .
* @ param data Arbitrary data .
* @ param from_admin Whether the origin is an admin or not .
*/
2023-05-08 19:01:06 +02:00
void NetworkServerSendChat ( NetworkAction action , DestType desttype , int dest , const std : : string & msg , ClientID from_id , int64_t data , bool from_admin )
2004-12-04 18:54:56 +01:00
{
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci , * ci_own , * ci_to ;
2004-12-04 18:54:56 +01:00
switch ( desttype ) {
2010-11-28 23:45:47 +01:00
case DESTTYPE_CLIENT :
/* Are we sending to the server? */
if ( ( ClientID ) dest = = CLIENT_ID_SERVER ) {
2011-04-22 17:54:16 +02:00
ci = NetworkClientInfo : : GetByClientID ( from_id ) ;
2010-11-28 23:45:47 +01:00
/* Display the text locally, and that is it */
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
2011-01-03 13:01:41 +01:00
NetworkTextMessage ( action , GetDrawStringCompanyColour ( ci - > client_playas ) , false , ci - > client_name , msg , data ) ;
2010-10-17 19:40:18 +02:00
2010-11-28 23:45:47 +01:00
if ( _settings_client . network . server_admin_chat ) {
2010-10-17 19:40:18 +02:00
NetworkAdminChat ( action , desttype , from_id , msg , data , from_admin ) ;
2010-11-28 23:45:47 +01:00
}
2010-07-24 12:14:39 +02:00
}
2004-12-04 18:54:56 +01:00
} else {
2010-11-28 23:45:47 +01:00
/* Else find the client to send the message to */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-28 23:45:47 +01:00
if ( cs - > client_id = = ( ClientID ) dest ) {
cs - > SendChat ( action , from_id , false , msg , data ) ;
2004-12-04 18:54:56 +01:00
break ;
}
}
}
2010-11-28 23:45:47 +01:00
/* Display the message locally (so you know you have sent it) */
if ( from_id ! = ( ClientID ) dest ) {
if ( from_id = = CLIENT_ID_SERVER ) {
2011-04-22 17:54:16 +02:00
ci = NetworkClientInfo : : GetByClientID ( from_id ) ;
ci_to = NetworkClientInfo : : GetByClientID ( ( ClientID ) dest ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr & & ci_to ! = nullptr ) {
2011-01-03 13:01:41 +01:00
NetworkTextMessage ( action , GetDrawStringCompanyColour ( ci - > client_playas ) , true , ci_to - > client_name , msg , data ) ;
2010-11-28 23:45:47 +01:00
}
} else {
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-28 23:45:47 +01:00
if ( cs - > client_id = = from_id ) {
cs - > SendChat ( action , ( ClientID ) dest , true , msg , data ) ;
break ;
}
}
}
}
break ;
case DESTTYPE_TEAM : {
/* If this is false, the message is already displayed on the client who sent it. */
bool show_local = true ;
/* Find all clients that belong to this company */
2019-04-10 23:07:06 +02:00
ci_to = nullptr ;
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-28 23:45:47 +01:00
ci = cs - > GetInfo ( ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr & & ci - > client_playas = = ( CompanyID ) dest ) {
2010-11-28 23:45:47 +01:00
cs - > SendChat ( action , from_id , false , msg , data ) ;
if ( cs - > client_id = = from_id ) show_local = false ;
ci_to = ci ; // Remember a client that is in the company for company-name
}
2004-12-04 18:54:56 +01:00
}
2004-12-20 16:26:19 +01:00
2010-11-28 23:45:47 +01:00
/* if the server can read it, let the admin network read it, too. */
if ( _local_company = = ( CompanyID ) dest & & _settings_client . network . server_admin_chat ) {
NetworkAdminChat ( action , desttype , from_id , msg , data , from_admin ) ;
}
2010-10-17 19:40:18 +02:00
2011-04-22 17:54:16 +02:00
ci = NetworkClientInfo : : GetByClientID ( from_id ) ;
ci_own = NetworkClientInfo : : GetByClientID ( CLIENT_ID_SERVER ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr & & ci_own ! = nullptr & & ci_own - > client_playas = = dest ) {
2011-01-03 13:01:41 +01:00
NetworkTextMessage ( action , GetDrawStringCompanyColour ( ci - > client_playas ) , false , ci - > client_name , msg , data ) ;
2010-11-28 23:45:47 +01:00
if ( from_id = = CLIENT_ID_SERVER ) show_local = false ;
ci_to = ci_own ;
}
2004-12-04 18:54:56 +01:00
2010-11-28 23:45:47 +01:00
/* There is no such client */
2019-04-10 23:07:06 +02:00
if ( ci_to = = nullptr ) break ;
2010-11-28 23:45:47 +01:00
/* Display the message locally (so you know you have sent it) */
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr & & show_local ) {
2010-11-28 23:45:47 +01:00
if ( from_id = = CLIENT_ID_SERVER ) {
StringID str = Company : : IsValidID ( ci_to - > client_playas ) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS ;
SetDParam ( 0 , ci_to - > client_playas ) ;
2021-05-14 18:45:54 +02:00
std : : string name = GetString ( str ) ;
2011-01-03 13:01:41 +01:00
NetworkTextMessage ( action , GetDrawStringCompanyColour ( ci_own - > client_playas ) , true , name , msg , data ) ;
2010-11-28 23:45:47 +01:00
} else {
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-28 23:45:47 +01:00
if ( cs - > client_id = = from_id ) {
cs - > SendChat ( action , ci_to - > client_id , true , msg , data ) ;
}
2004-12-04 18:54:56 +01:00
}
}
}
2010-11-28 23:45:47 +01:00
break ;
2004-12-04 18:54:56 +01:00
}
2010-11-28 23:45:47 +01:00
default :
2021-06-12 09:10:17 +02:00
Debug ( net , 1 , " Received unknown chat destination type {}; doing broadcast instead " , desttype ) ;
2024-01-31 21:03:17 +01:00
[[fallthrough]] ;
2017-08-13 20:38:42 +02:00
2010-11-28 23:45:47 +01:00
case DESTTYPE_BROADCAST :
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-28 23:45:47 +01:00
cs - > SendChat ( action , from_id , false , msg , data ) ;
}
2010-10-17 19:40:18 +02:00
2010-11-28 23:45:47 +01:00
NetworkAdminChat ( action , desttype , from_id , msg , data , from_admin ) ;
2010-10-17 19:40:18 +02:00
2011-04-22 17:54:16 +02:00
ci = NetworkClientInfo : : GetByClientID ( from_id ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
2021-09-19 23:09:06 +02:00
NetworkTextMessage ( action , GetDrawStringCompanyColour ( ci - > client_playas ) , false , ci - > client_name , msg , data , " " ) ;
2010-11-28 23:45:47 +01:00
}
break ;
2004-12-04 18:54:56 +01:00
}
}
2021-09-19 23:09:06 +02:00
/**
* Send a chat message from external source .
* @ param source Name of the source this message came from .
* @ param colour TextColour to use for the message .
* @ param user Name of the user who sent the messsage .
* @ param msg The actual message .
*/
void NetworkServerSendExternalChat ( const std : : string & source , TextColour colour , const std : : string & user , const std : : string & msg )
{
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
cs - > SendExternalChat ( source , colour , user , msg ) ;
}
NetworkTextMessage ( NETWORK_ACTION_EXTERNAL_CHAT , colour , false , user , msg , 0 , source ) ;
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_CHAT ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2012-02-16 21:45:03 +01:00
if ( this - > status < STATUS_PRE_ACTIVE ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_AUTHORIZED ) ;
2008-06-08 10:44:19 +02:00
}
2007-02-02 00:26:44 +01:00
NetworkAction action = ( NetworkAction ) p - > Recv_uint8 ( ) ;
DestType desttype = ( DestType ) p - > Recv_uint8 ( ) ;
2008-12-22 13:59:31 +01:00
int dest = p - > Recv_uint32 ( ) ;
2004-12-04 18:54:56 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_CHAT(): action={}, desttype={}, dest={} " , this - > client_id , action , desttype , dest ) ;
2021-05-14 18:22:39 +02:00
std : : string msg = p - > Recv_string ( NETWORK_CHAT_LENGTH ) ;
2023-05-08 19:01:06 +02:00
int64_t data = p - > Recv_uint64 ( ) ;
2004-12-04 18:54:56 +01:00
2010-10-15 15:47:37 +02:00
NetworkClientInfo * ci = this - > GetInfo ( ) ;
2008-07-21 17:50:55 +02:00
switch ( action ) {
case NETWORK_ACTION_CHAT :
case NETWORK_ACTION_CHAT_CLIENT :
case NETWORK_ACTION_CHAT_COMPANY :
2010-10-15 15:47:37 +02:00
NetworkServerSendChat ( action , desttype , dest , msg , this - > client_id , data ) ;
2008-07-21 17:50:55 +02:00
break ;
default :
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Kicking client #{} (IP: {}) due to unknown chact action. " , ci - > client_id , this - > GetClientIP ( ) ) ;
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2008-07-21 17:50:55 +02:00
}
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_SET_PASSWORD ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_ACTIVE ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2008-06-08 10:44:19 +02:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_SET_PASSWORD() " , this - > client_id ) ;
2021-05-02 09:07:09 +02:00
std : : string password = p - > Recv_string ( NETWORK_PASSWORD_LENGTH ) ;
const NetworkClientInfo * ci = this - > GetInfo ( ) ;
2004-12-04 18:54:56 +01:00
2011-01-19 17:47:40 +01:00
NetworkServerSetCompanyPassword ( ci - > client_playas , password ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_SET_NAME ( Packet * p )
2004-12-04 18:54:56 +01:00
{
2010-10-15 15:47:37 +02:00
if ( this - > status ! = STATUS_ACTIVE ) {
2008-06-08 10:44:19 +02:00
/* Illegal call, return error and ignore the packet */
2010-10-15 22:25:07 +02:00
return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2008-06-08 10:44:19 +02:00
}
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_SET_NAME() " , this - > client_id ) ;
2004-12-04 18:54:56 +01:00
NetworkClientInfo * ci ;
2021-05-29 20:22:41 +02:00
std : : string client_name = p - > Recv_string ( NETWORK_CLIENT_NAME_LENGTH ) ;
2010-10-15 15:47:37 +02:00
ci = this - > GetInfo ( ) ;
2004-12-04 18:54:56 +01:00
2021-05-11 12:26:16 +02:00
if ( this - > HasClientQuit ( ) ) return NETWORK_RECV_STATUS_CLIENT_QUIT ;
2005-01-05 15:39:48 +01:00
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
2021-04-22 08:17:36 +02:00
if ( ! NetworkIsValidClientName ( client_name ) ) {
/* An invalid client name was given. However, the client ensures the name
* is valid before it is sent over the network , so something went horribly
* wrong . This is probably someone trying to troll us . */
return this - > SendError ( NETWORK_ERROR_INVALID_CLIENT_NAME ) ;
}
2009-03-15 01:32:18 +01:00
/* Display change */
2021-05-29 20:22:41 +02:00
if ( NetworkMakeClientNameUnique ( client_name ) ) {
2008-12-29 11:37:53 +01:00
NetworkTextMessage ( NETWORK_ACTION_NAME_CHANGE , CC_DEFAULT , false , ci - > client_name , client_name ) ;
2021-05-15 08:31:45 +02:00
ci - > client_name = client_name ;
2008-12-22 13:59:31 +01:00
NetworkUpdateClientInfo ( ci - > client_id ) ;
2004-12-04 18:54:56 +01:00
}
}
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2004-12-04 18:54:56 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_RCON ( Packet * p )
2005-01-15 21:09:16 +01:00
{
2010-10-24 22:30:53 +02:00
if ( this - > status ! = STATUS_ACTIVE ) return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2021-04-27 20:26:56 +02:00
if ( _settings_client . network . rcon_password . empty ( ) ) return NETWORK_RECV_STATUS_OKAY ;
2005-01-15 21:09:16 +01:00
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_RCON() " , this - > client_id ) ;
2021-05-02 09:15:12 +02:00
std : : string password = p - > Recv_string ( NETWORK_PASSWORD_LENGTH ) ;
2021-05-29 19:33:42 +02:00
std : : string command = p - > Recv_string ( NETWORK_RCONCOMMAND_LENGTH ) ;
2005-01-15 21:09:16 +01:00
2021-05-02 09:15:12 +02:00
if ( _settings_client . network . rcon_password . compare ( password ) ! = 0 ) {
2021-06-12 09:10:17 +02:00
Debug ( net , 1 , " [rcon] Wrong password from client-id {} " , this - > client_id ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2005-01-15 21:09:16 +01:00
}
2021-06-12 09:10:17 +02:00
Debug ( net , 3 , " [rcon] Client-id {} executed: {} " , this - > client_id , command ) ;
2005-01-15 21:09:16 +01:00
2010-10-15 15:47:37 +02:00
_redirect_console_to_client = this - > client_id ;
2023-06-28 22:40:03 +02:00
IConsoleCmdExec ( command ) ;
2008-12-22 13:59:31 +01:00
_redirect_console_to_client = INVALID_CLIENT_ID ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2005-01-15 21:09:16 +01:00
}
2011-05-01 13:30:03 +02:00
NetworkRecvStatus ServerNetworkGameSocketHandler : : Receive_CLIENT_MOVE ( Packet * p )
2009-01-23 23:18:06 +01:00
{
2010-10-24 22:30:53 +02:00
if ( this - > status ! = STATUS_ACTIVE ) return this - > SendError ( NETWORK_ERROR_NOT_EXPECTED ) ;
2009-01-23 23:18:06 +01:00
CompanyID company_id = ( Owner ) p - > Recv_uint8 ( ) ;
2024-01-31 19:36:41 +01:00
Debug ( net , 9 , " client[{}] Receive_CLIENT_MOVE(): company_id={} " , this - > client_id , company_id ) ;
2009-06-23 14:11:35 +02:00
/* Check if the company is valid, we don't allow moving to AI companies */
2009-09-22 22:44:14 +02:00
if ( company_id ! = COMPANY_SPECTATOR & & ! Company : : IsValidHumanID ( company_id ) ) return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
/* Check if we require a password for this company */
2021-05-02 08:27:06 +02:00
if ( company_id ! = COMPANY_SPECTATOR & & ! _network_company_states [ company_id ] . password . empty ( ) ) {
2009-01-23 23:18:06 +01:00
/* we need a password from the client - should be in this packet */
2021-05-02 09:07:09 +02:00
std : : string password = p - > Recv_string ( NETWORK_PASSWORD_LENGTH ) ;
2009-01-23 23:18:06 +01:00
/* Incorrect password sent, return! */
2021-05-02 08:27:06 +02:00
if ( _network_company_states [ company_id ] . password . compare ( password ) ! = 0 ) {
2021-06-12 09:10:17 +02:00
Debug ( net , 2 , " Wrong password from client-id #{} for company #{} " , this - > client_id , company_id + 1 ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
}
/* if we get here we can move the client */
2010-10-15 15:47:37 +02:00
NetworkServerDoMove ( this - > client_id , company_id ) ;
2009-09-22 22:44:14 +02:00
return NETWORK_RECV_STATUS_OKAY ;
2009-01-23 23:18:06 +01:00
}
2008-12-22 19:40:57 +01:00
/**
* Populate the company stats .
* @ param stats the stats to update
*/
void NetworkPopulateCompanyStats ( NetworkCompanyStats * stats )
2004-12-04 18:54:56 +01:00
{
2008-12-22 19:40:57 +01:00
memset ( stats , 0 , sizeof ( * stats ) * MAX_COMPANIES ) ;
2004-12-04 18:54:56 +01:00
2008-12-22 19:40:57 +01:00
/* Go through all vehicles and count the type of vehicles */
2019-12-17 03:37:43 +01:00
for ( const Vehicle * v : Vehicle : : Iterate ( ) ) {
2009-05-17 03:00:56 +02:00
if ( ! Company : : IsValidID ( v - > owner ) | | ! v - > IsPrimaryVehicle ( ) ) continue ;
2008-01-13 23:27:06 +01:00
byte type = 0 ;
2006-06-27 23:25:53 +02:00
switch ( v - > type ) {
2010-06-19 18:37:56 +02:00
case VEH_TRAIN : type = NETWORK_VEH_TRAIN ; break ;
case VEH_ROAD : type = RoadVehicle : : From ( v ) - > IsBus ( ) ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY ; break ;
case VEH_AIRCRAFT : type = NETWORK_VEH_PLANE ; break ;
case VEH_SHIP : type = NETWORK_VEH_SHIP ; break ;
2008-01-13 23:27:06 +01:00
default : continue ;
2006-06-27 23:25:53 +02:00
}
2008-12-22 19:40:57 +01:00
stats [ v - > owner ] . num_vehicle [ type ] + + ;
2004-12-04 18:54:56 +01:00
}
2009-03-15 01:32:18 +01:00
/* Go through all stations and count the types of stations */
2019-12-15 05:55:59 +01:00
for ( const Station * s : Station : : Iterate ( ) ) {
2009-05-17 03:00:56 +02:00
if ( Company : : IsValidID ( s - > owner ) ) {
2008-12-22 19:40:57 +01:00
NetworkCompanyStats * npi = & stats [ s - > owner ] ;
2006-06-27 23:25:53 +02:00
2010-06-19 18:37:56 +02:00
if ( s - > facilities & FACIL_TRAIN ) npi - > num_station [ NETWORK_VEH_TRAIN ] + + ;
if ( s - > facilities & FACIL_TRUCK_STOP ) npi - > num_station [ NETWORK_VEH_LORRY ] + + ;
if ( s - > facilities & FACIL_BUS_STOP ) npi - > num_station [ NETWORK_VEH_BUS ] + + ;
if ( s - > facilities & FACIL_AIRPORT ) npi - > num_station [ NETWORK_VEH_PLANE ] + + ;
if ( s - > facilities & FACIL_DOCK ) npi - > num_station [ NETWORK_VEH_SHIP ] + + ;
2004-12-04 18:54:56 +01:00
}
}
}
2011-05-05 18:24:48 +02:00
/**
* Send updated client info of a particular client .
* @ param client_id The client to send it for .
*/
2008-12-22 13:59:31 +01:00
void NetworkUpdateClientInfo ( ClientID client_id )
2004-12-04 18:54:56 +01:00
{
2011-04-22 17:54:16 +02:00
NetworkClientInfo * ci = NetworkClientInfo : : GetByClientID ( client_id ) ;
2004-12-04 18:54:56 +01:00
2019-04-10 23:07:06 +02:00
if ( ci = = nullptr ) return ;
2004-12-14 21:27:00 +01:00
2024-01-22 15:04:34 +01:00
Debug ( desync , 1 , " client: {:08x}; {:02x}; {:02x}; {:04x} " , TimerGameEconomy : : date , TimerGameEconomy : : date_fract , ( int ) ci - > client_playas , client_id ) ;
2010-04-08 23:14:49 +02:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2021-04-06 20:31:52 +02:00
if ( cs - > status > = ServerNetworkGameSocketHandler : : STATUS_AUTHORIZED ) {
cs - > SendClientInfo ( ci ) ;
}
2004-12-04 18:54:56 +01:00
}
2010-10-17 19:37:26 +02:00
NetworkAdminClientUpdate ( ci ) ;
2004-12-04 18:54:56 +01:00
}
2011-05-05 18:24:48 +02:00
/** 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 )
*/
2007-03-07 12:47:46 +01:00
static void NetworkAutoCleanCompanies ( )
2004-12-16 14:59:23 +01:00
{
2024-01-05 21:58:24 +01:00
CompanyMask has_clients = 0 ;
CompanyMask has_vehicles = 0 ;
2004-12-16 14:59:23 +01:00
2008-05-29 22:21:28 +02:00
if ( ! _settings_client . network . autoclean_companies ) return ;
2004-12-16 14:59:23 +01:00
/* Detect the active companies */
2019-12-16 20:56:10 +01:00
for ( const NetworkClientInfo * ci : NetworkClientInfo : : Iterate ( ) ) {
2024-01-05 21:58:24 +01:00
if ( Company : : IsValidID ( ci - > client_playas ) ) SetBit ( has_clients , ci - > client_playas ) ;
2004-12-16 14:59:23 +01:00
}
2006-10-18 01:34:12 +02:00
2004-12-16 14:59:23 +01:00
if ( ! _network_dedicated ) {
2019-12-16 20:56:10 +01:00
const NetworkClientInfo * ci = NetworkClientInfo : : GetByClientID ( CLIENT_ID_SERVER ) ;
2023-01-06 23:43:50 +01:00
assert ( ci ! = nullptr ) ;
2024-01-05 21:58:24 +01:00
if ( Company : : IsValidID ( ci - > client_playas ) ) SetBit ( has_clients , ci - > client_playas ) ;
2004-12-16 14:59:23 +01:00
}
2009-03-25 17:30:33 +01:00
if ( _settings_client . network . autoclean_novehicles ! = 0 ) {
2024-01-05 21:58:24 +01:00
for ( const Company * c : Company : : Iterate ( ) ) {
if ( std : : any_of ( std : : begin ( c - > group_all ) , std : : end ( c - > group_all ) , [ ] ( const GroupStatistics & gs ) { return gs . num_vehicle ! = 0 ; } ) ) SetBit ( has_vehicles , c - > index ) ;
2009-03-25 17:30:33 +01:00
}
}
2013-01-08 23:46:42 +01:00
/* Go through all the companies */
2019-12-14 17:22:38 +01:00
for ( const Company * c : Company : : Iterate ( ) ) {
2004-12-16 14:59:23 +01:00
/* Skip the non-active once */
2008-09-30 22:39:50 +02:00
if ( c - > is_ai ) continue ;
2004-12-16 14:59:23 +01:00
2024-01-05 21:58:24 +01:00
if ( ! HasBit ( has_clients , c - > index ) ) {
2004-12-16 14:59:23 +01:00
/* The company is empty for one month more */
2008-12-22 19:40:57 +01:00
_network_company_states [ c - > index ] . months_empty + + ;
2004-12-16 14:59:23 +01:00
/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
2021-05-02 08:27:06 +02:00
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 ( ) ) {
2004-12-16 14:59:23 +01:00
/* Shut the company down */
2021-11-02 21:34:39 +01:00
Command < CMD_COMPANY_CTRL > : : Post ( CCA_DELETE , c - > index , CRR_AUTOCLEAN , INVALID_CLIENT_ID ) ;
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Auto-cleaned company #{} with no password. " , c - > index + 1 ) ;
2004-12-16 14:59:23 +01:00
}
2008-09-30 22:39:50 +02:00
/* Is the company empty for autoclean_protected-months, and there is a protection? */
2021-05-02 08:27:06 +02:00
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 ( ) ) {
2004-12-16 14:59:23 +01:00
/* Unprotect the company */
2021-05-02 08:27:06 +02:00
_network_company_states [ c - > index ] . password . clear ( ) ;
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Auto-removed protection from company #{}. " , c - > index + 1 ) ;
2008-12-22 19:40:57 +01:00
_network_company_states [ c - > index ] . months_empty = 0 ;
2009-01-23 23:18:06 +01:00
NetworkServerUpdateCompanyPassworded ( c - > index , false ) ;
2004-12-16 14:59:23 +01:00
}
2009-03-25 17:30:33 +01:00
/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
2024-01-05 21:58:24 +01:00
if ( _settings_client . network . autoclean_novehicles ! = 0 & & _network_company_states [ c - > index ] . months_empty > _settings_client . network . autoclean_novehicles & & ! HasBit ( has_vehicles , c - > index ) ) {
2009-03-25 17:30:33 +01:00
/* Shut the company down */
2021-11-02 21:34:39 +01:00
Command < CMD_COMPANY_CTRL > : : Post ( CCA_DELETE , c - > index , CRR_AUTOCLEAN , INVALID_CLIENT_ID ) ;
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Auto-cleaned company #{} with no vehicles. " , c - > index + 1 ) ;
2009-03-25 17:30:33 +01:00
}
2004-12-16 14:59:23 +01:00
} else {
/* It is not empty, reset the date */
2008-12-22 19:40:57 +01:00
_network_company_states [ c - > index ] . months_empty = 0 ;
2004-12-16 14:59:23 +01:00
}
}
}
2011-05-05 18:24:48 +02:00
/**
* Check whether a name is unique , and otherwise try to make it unique .
* @ param new_name The name to check / modify .
* @ return True if an unique name was achieved .
*/
2021-05-29 20:22:41 +02:00
bool NetworkMakeClientNameUnique ( std : : string & name )
2004-12-04 18:54:56 +01:00
{
2021-05-29 20:22:41 +02:00
bool is_name_unique = false ;
std : : string original_name = name ;
2004-12-04 18:54:56 +01:00
2021-08-16 11:09:54 +02:00
for ( uint number = 1 ; ! is_name_unique & & number < = MAX_CLIENTS ; number + + ) { // Something's really wrong when there're more names than clients
2021-05-29 20:22:41 +02:00
is_name_unique = true ;
2019-12-16 20:56:10 +01:00
for ( const NetworkClientInfo * ci : NetworkClientInfo : : Iterate ( ) ) {
2021-08-16 11:09:54 +02:00
if ( ci - > client_name = = name ) {
2008-12-23 16:23:31 +01:00
/* Name already in use */
2021-05-29 20:22:41 +02:00
is_name_unique = false ;
2004-12-04 18:54:56 +01:00
break ;
}
}
2008-12-23 16:23:31 +01:00
/* Check if it is the same as the server-name */
2019-12-16 20:56:10 +01:00
const NetworkClientInfo * ci = NetworkClientInfo : : GetByClientID ( CLIENT_ID_SERVER ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
2021-08-16 11:09:54 +02:00
if ( ci - > client_name = = name ) is_name_unique = false ; // name already in use
2004-12-04 18:54:56 +01:00
}
2021-05-29 20:22:41 +02:00
if ( ! is_name_unique ) {
2008-12-23 16:23:31 +01:00
/* Try a new name (<name> #1, <name> #2, and so on) */
2021-05-29 20:22:41 +02:00
name = original_name + " # " + std : : to_string ( number ) ;
2004-12-04 18:54:56 +01:00
2021-05-29 20:22:41 +02:00
/* The constructed client name is larger than the limit,
* so . . . bail out as no valid name can be created . */
if ( name . size ( ) > = NETWORK_CLIENT_NAME_LENGTH ) return false ;
2004-12-04 18:54:56 +01:00
}
}
2021-05-29 20:22:41 +02:00
return is_name_unique ;
2004-12-04 18:54:56 +01:00
}
2009-01-22 00:07:11 +01:00
/**
* Change the client name of the given client
* @ param client_id the client to change the name of
* @ param new_name the new name for the client
* @ return true iff the name was changed
*/
2021-05-29 19:29:14 +02:00
bool NetworkServerChangeClientName ( ClientID client_id , const std : : string & new_name )
2009-01-22 00:07:11 +01:00
{
/* Check if the name's already in use */
2019-12-16 20:56:10 +01:00
for ( NetworkClientInfo * ci : NetworkClientInfo : : Iterate ( ) ) {
2021-05-15 08:31:45 +02:00
if ( ci - > client_name . compare ( new_name ) = = 0 ) return false ;
2009-01-22 00:07:11 +01:00
}
2019-12-16 20:56:10 +01:00
NetworkClientInfo * ci = NetworkClientInfo : : GetByClientID ( client_id ) ;
2019-04-10 23:07:06 +02:00
if ( ci = = nullptr ) return false ;
2009-01-22 00:07:11 +01:00
NetworkTextMessage ( NETWORK_ACTION_NAME_CHANGE , CC_DEFAULT , true , ci - > client_name , new_name ) ;
2021-05-15 08:31:45 +02:00
ci - > client_name = new_name ;
2009-01-22 00:07:11 +01:00
NetworkUpdateClientInfo ( client_id ) ;
return true ;
}
2011-01-19 17:37:06 +01:00
/**
2011-01-19 17:47:40 +01:00
* 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 ?
2011-01-19 17:37:06 +01:00
*/
2021-05-02 09:07:09 +02:00
void NetworkServerSetCompanyPassword ( CompanyID company_id , const std : : string & password , bool already_hashed )
2011-01-19 17:37:06 +01:00
{
2011-01-19 17:47:40 +01:00
if ( ! Company : : IsValidHumanID ( company_id ) ) return ;
2011-01-19 17:37:06 +01:00
2021-05-02 09:07:09 +02:00
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 ) ;
2011-01-19 17:37:06 +01:00
}
2011-01-19 17:47:40 +01:00
2021-05-02 08:27:06 +02:00
NetworkServerUpdateCompanyPassworded ( company_id , ! _network_company_states [ company_id ] . password . empty ( ) ) ;
2011-01-19 17:37:06 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Handle the command - queue of a socket .
* @ param cs The socket to handle the queue for .
*/
2009-01-10 01:31:47 +01:00
static void NetworkHandleCommandQueue ( NetworkClientSocket * cs )
2006-01-05 13:40:50 +01:00
{
2005-07-16 17:05:52 +02:00
CommandPacket * cp ;
2019-04-10 23:07:06 +02:00
while ( ( cp = cs - > outgoing_queue . Pop ( ) ) ! = nullptr ) {
2010-10-15 22:25:07 +02:00
cs - > SendCommand ( cp ) ;
2021-06-03 22:07:44 +02:00
delete cp ;
2004-12-04 18:54:56 +01:00
}
}
2011-05-05 18:24:48 +02:00
/**
* This is called every tick if this is a _network_server
* @ param send_frame Whether to send the frame to the clients .
*/
2005-07-29 23:55:49 +02:00
void NetworkServer_Tick ( bool send_frame )
2004-12-04 18:54:56 +01:00
{
2005-07-16 14:59:23 +02:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
bool send_sync = false ;
# endif
2004-12-04 18:54:56 +01:00
2005-07-16 14:59:23 +02:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2008-05-29 22:21:28 +02:00
if ( _frame_counter > = _last_sync_frame + _settings_client . network . sync_freq ) {
2005-07-16 14:59:23 +02:00
_last_sync_frame = _frame_counter ;
send_sync = true ;
}
# endif
2009-03-15 01:32:18 +01:00
/* Now we are done with the frame, inform the clients that they can
* do their frame ! */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-11-30 21:01:26 +01:00
/* We allow a number of bytes per frame, but only to the burst amount
* to be available for packet receiving at any particular time . */
2021-04-18 12:29:34 +02:00
cs - > receive_limit = std : : min < size_t > ( cs - > receive_limit + _settings_client . network . bytes_per_frame ,
2010-11-30 21:01:26 +01:00
_settings_client . network . bytes_per_frame_burst ) ;
2009-03-15 01:32:18 +01:00
/* Check if the speed of the client is what we can expect from a client */
2012-01-06 22:49:06 +01:00
uint lag = NetworkCalculateLag ( cs ) ;
switch ( cs - > status ) {
case NetworkClientSocket : : STATUS_ACTIVE :
2012-01-07 15:43:45 +01:00
if ( lag > _settings_client . network . max_lag_time ) {
2013-01-08 23:46:42 +01:00
/* Client did still not report in within the specified limit. */
2024-01-16 22:04:35 +01:00
if ( cs - > last_packet + std : : chrono : : milliseconds ( lag * MILLISECONDS_PER_TICK ) > std : : chrono : : steady_clock : : now ( ) ) {
/* A packet was received in the last three game days, so the client is likely lagging behind. */
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because the client's game state is more than {} ticks behind. " , cs - > client_id , cs - > GetClientIP ( ) , lag ) ;
} else {
/* No packet was received in the last three game days; sounds like a lost connection. */
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because the client did not respond for more than {} ticks. " , cs - > client_id , cs - > GetClientIP ( ) , lag ) ;
}
2012-01-07 15:43:45 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_COMPUTER ) ;
continue ;
}
2012-01-06 22:49:06 +01:00
2012-01-07 15:43:45 +01:00
/* Report once per time we detect the lag, and only when we
2021-02-25 20:30:16 +01:00
* received a packet in the last 2 seconds . If we
2012-01-07 15:43:45 +01:00
* did not receive a packet , then the client is not just
* slow , but the connection is likely severed . Mentioning
* frame_freq is not useful in this case . */
2023-08-16 15:01:24 +02:00
if ( lag > ( uint ) Ticks : : DAY_TICKS & & cs - > lag_test = = 0 & & cs - > last_packet + std : : chrono : : seconds ( 2 ) > std : : chrono : : steady_clock : : now ( ) ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " [{}] Client #{} is slow, try increasing [network.]frame_freq to a higher value! " , _frame_counter , cs - > client_id ) ;
2012-01-07 15:43:45 +01:00
cs - > lag_test = 1 ;
2012-01-06 22:49:06 +01:00
}
2012-01-07 15:43:45 +01:00
if ( cs - > last_frame_server - cs - > last_token_frame > = _settings_client . network . max_lag_time ) {
/* This is a bad client! It didn't send the right token back within time. */
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because it fails to send valid acks. " , cs - > client_id , cs - > GetClientIP ( ) ) ;
2012-01-06 22:49:06 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_COMPUTER ) ;
2004-12-04 18:54:56 +01:00
continue ;
}
2012-01-06 22:49:06 +01:00
break ;
2004-12-04 18:54:56 +01:00
2012-01-06 22:49:06 +01:00
case NetworkClientSocket : : STATUS_INACTIVE :
case NetworkClientSocket : : STATUS_NEWGRFS_CHECK :
case NetworkClientSocket : : STATUS_AUTHORIZED :
/* NewGRF check and authorized states should be handled almost instantly.
* So give them some lee - way , likewise for the query with inactive . */
2012-01-07 15:43:45 +01:00
if ( lag > _settings_client . network . max_init_time ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because it took longer than {} ticks to start the joining process. " , cs - > client_id , cs - > GetClientIP ( ) , _settings_client . network . max_init_time ) ;
2012-01-06 22:49:06 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_COMPUTER ) ;
continue ;
2004-12-04 18:54:56 +01:00
}
2012-01-06 22:49:06 +01:00
break ;
2021-02-27 10:54:16 +01:00
case NetworkClientSocket : : STATUS_MAP_WAIT :
/* Send every two seconds a packet to the client, to make sure
2021-05-08 12:02:30 +02:00
* it knows the server is still there ; just someone else is
2021-02-27 10:54:16 +01:00
* still receiving the map . */
if ( std : : chrono : : steady_clock : : now ( ) > cs - > last_packet + std : : chrono : : seconds ( 2 ) ) {
cs - > SendWait ( ) ;
/* We need to reset the timer, as otherwise we will be
* spamming the client . Strictly speaking this variable
* tracks when we last received a packet from the client ,
2021-05-08 12:02:30 +02:00
* but as it is waiting , it will not send us any till we
2021-05-09 19:02:17 +02:00
* start sending them data . */
2021-02-27 10:54:16 +01:00
cs - > last_packet = std : : chrono : : steady_clock : : now ( ) ;
}
break ;
2012-01-06 22:49:06 +01:00
case NetworkClientSocket : : STATUS_MAP :
/* Downloading the map... this is the amount of time since starting the saving. */
if ( lag > _settings_client . network . max_download_time ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because it took longer than {} ticks to download the map. " , cs - > client_id , cs - > GetClientIP ( ) , _settings_client . network . max_download_time ) ;
2012-01-09 22:22:48 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_MAP ) ;
2012-01-06 22:49:06 +01:00
continue ;
}
break ;
case NetworkClientSocket : : STATUS_DONE_MAP :
case NetworkClientSocket : : STATUS_PRE_ACTIVE :
/* The map has been sent, so this is for loading the map and syncing up. */
if ( lag > _settings_client . network . max_join_time ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_WARNING , " Client #{} (IP: {}) is dropped because it took longer than {} ticks to join. " , cs - > client_id , cs - > GetClientIP ( ) , _settings_client . network . max_join_time ) ;
2012-01-09 22:22:48 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_JOIN ) ;
2012-01-06 22:49:06 +01:00
continue ;
}
break ;
case NetworkClientSocket : : STATUS_AUTH_GAME :
case NetworkClientSocket : : STATUS_AUTH_COMPANY :
/* These don't block? */
if ( lag > _settings_client . network . max_password_time ) {
2021-06-12 21:31:57 +02:00
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 ) ;
2012-01-06 22:49:06 +01:00
cs - > SendError ( NETWORK_ERROR_TIMEOUT_PASSWORD ) ;
continue ;
}
break ;
case NetworkClientSocket : : STATUS_END :
/* Bad server/code. */
NOT_REACHED ( ) ;
2004-12-04 18:54:56 +01:00
}
2010-10-24 22:07:32 +02:00
if ( cs - > status > = NetworkClientSocket : : STATUS_PRE_ACTIVE ) {
2009-03-15 01:32:18 +01:00
/* Check if we can send command, and if we have anything in the queue */
2004-12-04 18:54:56 +01:00
NetworkHandleCommandQueue ( cs ) ;
2009-03-15 01:32:18 +01:00
/* Send an updated _frame_counter_max to the client */
2010-10-15 22:25:07 +02:00
if ( send_frame ) cs - > SendFrame ( ) ;
2004-12-04 18:54:56 +01:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2009-03-15 01:32:18 +01:00
/* Send a sync-check packet */
2010-10-15 22:25:07 +02:00
if ( send_sync ) cs - > SendSync ( ) ;
2004-12-04 18:54:56 +01:00
# endif
2005-07-16 14:59:23 +02:00
}
}
2004-12-04 18:54:56 +01:00
}
2024-01-26 16:25:25 +01:00
/** Helper function to restart the map. */
static void NetworkRestartMap ( )
{
_settings_newgame . game_creation . generation_seed = GENERATE_NEW_SEED ;
switch ( _file_to_saveload . abstract_ftype ) {
case FT_SAVEGAME :
case FT_SCENARIO :
_switch_mode = SM_LOAD_GAME ;
break ;
case FT_HEIGHTMAP :
_switch_mode = SM_START_HEIGHTMAP ;
break ;
default :
_switch_mode = SM_NEWGAME ;
}
}
/** Timer to restart a network server automatically based on real-time hours played. Initialized at zero to disable until settings are loaded. */
static IntervalTimer < TimerGameRealtime > _network_restart_map_timer ( { std : : chrono : : hours : : zero ( ) , TimerGameRealtime : : UNPAUSED } , [ ] ( auto )
{
if ( ! _network_server ) return ;
/* If setting is 0, this feature is disabled. */
if ( _settings_client . network . restart_hours = = 0 ) return ;
Debug ( net , 3 , " Auto-restarting map: {} hours played " , _settings_client . network . restart_hours ) ;
NetworkRestartMap ( ) ;
} ) ;
/**
* Reset the automatic network restart time interval .
* @ param reset Whether to reset the timer to zero .
*/
void ChangeNetworkRestartTime ( bool reset )
{
if ( ! _network_server ) return ;
_network_restart_map_timer . SetInterval ( { std : : chrono : : hours ( _settings_client . network . restart_hours ) , TimerGameRealtime : : UNPAUSED } , reset ) ;
}
/** Check if we want to restart the map based on the year. */
static void NetworkCheckRestartMapYear ( )
{
/* If setting is 0, this feature is disabled. */
if ( _settings_client . network . restart_game_year = = 0 ) return ;
if ( TimerGameCalendar : : year > = _settings_client . network . restart_game_year ) {
Debug ( net , 3 , " Auto-restarting map: year {} reached " , TimerGameCalendar : : year ) ;
NetworkRestartMap ( ) ;
}
}
2024-01-22 15:04:34 +01:00
/** Calendar yearly "callback". Called whenever the calendar year changes. */
static IntervalTimer < TimerGameCalendar > _calendar_network_yearly ( { TimerGameCalendar : : YEAR , TimerGameCalendar : : Priority : : NONE } , [ ] ( auto ) {
2023-04-13 13:56:00 +02:00
if ( ! _network_server ) return ;
2024-01-26 16:25:25 +01:00
NetworkCheckRestartMapYear ( ) ;
2024-01-22 15:04:34 +01:00
} ) ;
/** Economy yearly "callback". Called whenever the economy year changes. */
static IntervalTimer < TimerGameEconomy > _economy_network_yearly ( { TimerGameEconomy : : YEAR , TimerGameEconomy : : Priority : : NONE } , [ ] ( auto )
{
if ( ! _network_server ) return ;
2010-10-17 19:36:23 +02:00
NetworkAdminUpdate ( ADMIN_FREQUENCY_ANUALLY ) ;
2023-04-13 13:56:00 +02:00
} ) ;
2004-12-23 18:37:26 +01:00
2024-01-22 15:04:34 +01:00
/** Quarterly "callback". Called whenever the economy quarter changes. */
static IntervalTimer < TimerGameEconomy > _network_quarterly ( { TimerGameEconomy : : QUARTER , TimerGameEconomy : : Priority : : NONE } , [ ] ( auto )
2023-08-12 16:02:11 +02:00
{
if ( ! _network_server ) return ;
NetworkAutoCleanCompanies ( ) ;
NetworkAdminUpdate ( ADMIN_FREQUENCY_QUARTERLY ) ;
} ) ;
2024-01-22 15:04:34 +01:00
/** Economy monthly "callback". Called whenever the economy month changes. */
static IntervalTimer < TimerGameEconomy > _network_monthly ( { TimerGameEconomy : : MONTH , TimerGameEconomy : : Priority : : NONE } , [ ] ( auto )
2004-12-16 14:59:23 +01:00
{
2023-04-13 13:56:00 +02:00
if ( ! _network_server ) return ;
2004-12-16 14:59:23 +01:00
NetworkAutoCleanCompanies ( ) ;
2010-10-17 19:36:23 +02:00
NetworkAdminUpdate ( ADMIN_FREQUENCY_MONTHLY ) ;
2023-08-12 16:02:11 +02:00
} ) ;
2024-01-22 15:04:34 +01:00
/** Economy weekly "callback". Called whenever the economy week changes. */
static IntervalTimer < TimerGameEconomy > _network_weekly ( { TimerGameEconomy : : WEEK , TimerGameEconomy : : Priority : : NONE } , [ ] ( auto )
2023-08-12 16:02:11 +02:00
{
if ( ! _network_server ) return ;
NetworkAdminUpdate ( ADMIN_FREQUENCY_WEEKLY ) ;
2023-04-13 13:56:00 +02:00
} ) ;
2010-10-17 19:36:23 +02:00
2024-01-22 15:04:34 +01:00
/** Daily "callback". Called whenever the economy date changes. */
static IntervalTimer < TimerGameEconomy > _economy_network_daily ( { TimerGameEconomy : : DAY , TimerGameEconomy : : Priority : : NONE } , [ ] ( auto )
2010-10-17 19:36:23 +02:00
{
2023-04-13 13:56:00 +02:00
if ( ! _network_server ) return ;
2010-10-17 19:36:23 +02:00
NetworkAdminUpdate ( ADMIN_FREQUENCY_DAILY ) ;
2023-04-13 13:56:00 +02:00
} ) ;
2004-12-16 14:59:23 +01:00
2011-04-22 18:02:21 +02:00
/**
* Get the IP address / hostname of the connected client .
* @ return The IP address .
*/
2021-06-13 21:05:15 +02:00
const std : : string & ServerNetworkGameSocketHandler : : GetClientIP ( )
2008-05-30 20:20:26 +02:00
{
2011-04-22 18:03:48 +02:00
return this - > client_address . GetHostname ( ) ;
2008-05-30 20:20:26 +02:00
}
2011-05-05 18:24:48 +02:00
/** Show the status message of all clients on the console. */
2008-05-30 20:20:26 +02:00
void NetworkServerShowStatusToConsole ( )
{
2009-01-10 01:31:47 +01:00
static const char * const stat_str [ ] = {
2008-05-30 20:20:26 +02:00
" inactive " ,
2010-04-22 19:26:57 +02:00
" checking NewGRFs " ,
2010-04-19 21:50:56 +02:00
" authorizing (server password) " ,
" authorizing (company password) " ,
2008-05-30 20:20:26 +02:00
" authorized " ,
" waiting " ,
" loading map " ,
" map done " ,
" ready " ,
" active "
} ;
2020-12-27 11:44:22 +01:00
static_assert ( lengthof ( stat_str ) = = NetworkClientSocket : : STATUS_END ) ;
2008-05-30 20:20:26 +02:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2009-04-04 02:48:48 +02:00
NetworkClientInfo * ci = cs - > GetInfo ( ) ;
2019-04-10 23:07:06 +02:00
if ( ci = = nullptr ) continue ;
2011-04-22 18:05:05 +02:00
uint lag = NetworkCalculateLag ( cs ) ;
2009-01-10 01:31:47 +01:00
const char * status ;
2008-05-30 20:20:26 +02:00
status = ( cs - > status < ( ptrdiff_t ) lengthof ( stat_str ) ? stat_str [ cs - > status ] : " unknown " ) ;
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Client #{} name: '{}' status: '{}' frame-lag: {} company: {} IP: {} " ,
2023-06-15 19:15:08 +02:00
cs - > client_id , ci - > client_name , status , lag ,
2009-05-17 03:00:56 +02:00
ci - > client_playas + ( Company : : IsValidID ( ci - > client_playas ) ? 1 : 0 ) ,
2011-04-22 18:02:21 +02:00
cs - > GetClientIP ( ) ) ;
2008-05-30 20:20:26 +02:00
}
}
2009-01-23 23:18:06 +01:00
/**
* Send Config Update
*/
void NetworkServerSendConfigUpdate ( )
{
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-10-24 22:30:53 +02:00
if ( cs - > status > = NetworkClientSocket : : STATUS_PRE_ACTIVE ) cs - > SendConfigUpdate ( ) ;
2009-01-23 23:18:06 +01:00
}
}
2021-05-05 19:21:12 +02:00
/** Update the server's NetworkServerGameInfo due to changes in settings. */
void NetworkServerUpdateGameInfo ( )
{
if ( _network_server ) FillStaticNetworkServerGameInfo ( ) ;
}
2011-05-05 18:24:48 +02:00
/**
* 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 .
*/
2009-01-23 23:18:06 +01:00
void NetworkServerUpdateCompanyPassworded ( CompanyID company_id , bool passworded )
{
if ( NetworkCompanyIsPassworded ( company_id ) = = passworded ) return ;
SB ( _network_company_passworded , company_id , 1 , ! ! passworded ) ;
2009-09-13 21:15:59 +02:00
SetWindowClassesDirty ( WC_COMPANY ) ;
2009-01-23 23:18:06 +01:00
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2010-10-24 22:30:53 +02:00
if ( cs - > status > = NetworkClientSocket : : STATUS_PRE_ACTIVE ) cs - > SendCompanyUpdate ( ) ;
2009-01-23 23:18:06 +01:00
}
2011-01-04 23:28:02 +01:00
NetworkAdminCompanyUpdate ( Company : : GetIfValid ( company_id ) ) ;
2009-01-23 23:18:06 +01:00
}
/**
* Handle the tid - bits of moving a client from one company to another .
* @ param client_id id of the client we want to move .
* @ param company_id id of the company we want to move the client to .
* @ return void
2010-08-01 21:44:49 +02:00
*/
2009-01-23 23:18:06 +01:00
void NetworkServerDoMove ( ClientID client_id , CompanyID company_id )
{
/* Only allow non-dedicated servers and normal clients to be moved */
if ( client_id = = CLIENT_ID_SERVER & & _network_dedicated ) return ;
2011-04-22 17:54:16 +02:00
NetworkClientInfo * ci = NetworkClientInfo : : GetByClientID ( client_id ) ;
2023-01-06 23:43:50 +01:00
assert ( ci ! = nullptr ) ;
2009-01-23 23:18:06 +01:00
/* No need to waste network resources if the client is in the company already! */
if ( ci - > client_playas = = company_id ) return ;
ci - > client_playas = company_id ;
if ( client_id = = CLIENT_ID_SERVER ) {
SetLocalCompany ( company_id ) ;
} else {
2011-04-22 17:54:42 +02:00
NetworkClientSocket * cs = NetworkClientSocket : : GetByClientID ( client_id ) ;
2010-10-24 22:30:53 +02:00
/* When the company isn't authorized we can't move them yet. */
if ( cs - > status < NetworkClientSocket : : STATUS_AUTHORIZED ) return ;
cs - > SendMove ( client_id , company_id ) ;
2009-01-23 23:18:06 +01:00
}
/* announce the client's move */
NetworkUpdateClientInfo ( client_id ) ;
NetworkAction action = ( company_id = = COMPANY_SPECTATOR ) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN ;
NetworkServerSendChat ( action , DESTTYPE_BROADCAST , 0 , " " , client_id , company_id + 1 ) ;
2021-04-18 09:54:47 +02:00
InvalidateWindowData ( WC_CLIENT_LIST , 0 ) ;
2009-01-23 23:18:06 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Send an rcon reply to the client .
* @ param client_id The identifier of the client .
* @ param colour_code The colour of the text .
* @ param string The actual reply .
*/
2021-05-29 19:33:42 +02:00
void NetworkServerSendRcon ( ClientID client_id , TextColour colour_code , const std : : string & string )
2008-05-30 20:20:26 +02:00
{
2011-04-22 17:54:42 +02:00
NetworkClientSocket : : GetByClientID ( client_id ) - > SendRConResult ( colour_code , string ) ;
2008-05-30 20:20:26 +02:00
}
2011-05-05 18:24:48 +02:00
/**
* Kick a single client .
* @ param client_id The client to kick .
2020-01-21 16:39:10 +01:00
* @ param reason In case of kicking a client , specifies the reason for kicking the client .
2011-05-05 18:24:48 +02:00
*/
2021-05-29 19:47:58 +02:00
void NetworkServerKickClient ( ClientID client_id , const std : : string & reason )
2009-03-06 13:42:01 +01:00
{
if ( client_id = = CLIENT_ID_SERVER ) return ;
2020-01-21 16:39:10 +01:00
NetworkClientSocket : : GetByClientID ( client_id ) - > SendError ( NETWORK_ERROR_KICKED , reason ) ;
2009-03-06 13:42:01 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Ban , or kick , everyone joined from the given client ' s IP .
* @ param client_id The client to check for .
* @ param ban Whether to ban or kick .
2020-01-21 16:39:10 +01:00
* @ param reason In case of kicking a client , specifies the reason for kicking the client .
2011-05-05 18:24:48 +02:00
*/
2021-05-29 19:47:58 +02:00
uint NetworkServerKickOrBanIP ( ClientID client_id , bool ban , const std : : string & reason )
2011-04-22 17:59:32 +02:00
{
2020-01-21 16:39:10 +01:00
return NetworkServerKickOrBanIP ( NetworkClientSocket : : GetByClientID ( client_id ) - > GetClientIP ( ) , ban , reason ) ;
2011-04-22 17:59:32 +02:00
}
2011-05-05 18:24:48 +02:00
/**
* Kick or ban someone based on an IP address .
* @ param ip The IP address / range to ban / kick .
* @ param ban Whether to ban or just kick .
2020-01-21 16:39:10 +01:00
* @ param reason In case of kicking a client , specifies the reason for kicking the client .
2011-05-05 18:24:48 +02:00
*/
2021-05-29 19:47:58 +02:00
uint NetworkServerKickOrBanIP ( const std : : string & ip , bool ban , const std : : string & reason )
2009-03-06 13:42:01 +01:00
{
2010-05-13 18:00:50 +02:00
/* Add address to ban-list */
2012-10-09 22:36:31 +02:00
if ( ban ) {
bool contains = false ;
2019-04-02 21:31:33 +02:00
for ( const auto & iter : _network_ban_list ) {
if ( iter = = ip ) {
2012-10-09 22:36:31 +02:00
contains = true ;
break ;
}
}
2019-04-02 21:31:33 +02:00
if ( ! contains ) _network_ban_list . emplace_back ( ip ) ;
2012-10-09 22:36:31 +02:00
}
2010-05-13 18:00:50 +02:00
uint n = 0 ;
2009-03-06 13:42:01 +01:00
2020-02-07 23:19:57 +01:00
/* There can be multiple clients with the same IP, kick them all but don't kill the server,
* or the client doing the rcon . The latter can ' t be kicked because kicking frees closes
* and subsequently free the connection related instances , which we would be reading from
* and writing to after returning . So we would read or write data from freed memory up till
* the segfault triggers . */
2019-12-16 20:56:10 +01:00
for ( NetworkClientSocket * cs : NetworkClientSocket : : Iterate ( ) ) {
2011-04-22 18:03:48 +02:00
if ( cs - > client_id = = CLIENT_ID_SERVER ) continue ;
2020-02-07 23:19:57 +01:00
if ( cs - > client_id = = _redirect_console_to_client ) continue ;
2021-06-13 21:05:15 +02:00
if ( cs - > client_address . IsInNetmask ( ip ) ) {
2020-01-21 16:39:10 +01:00
NetworkServerKickClient ( cs - > client_id , reason ) ;
2010-05-13 18:00:50 +02:00
n + + ;
2009-03-06 13:42:01 +01:00
}
}
2010-05-13 18:00:50 +02:00
return n ;
2009-03-06 13:42:01 +01:00
}
2011-05-05 18:24:48 +02:00
/**
* Check whether a particular company has clients .
* @ param company The company to check .
* @ return True if at least one client is joined to the company .
*/
2008-09-30 22:39:50 +02:00
bool NetworkCompanyHasClients ( CompanyID company )
2008-05-30 20:20:26 +02:00
{
2019-12-16 20:56:10 +01:00
for ( const NetworkClientInfo * ci : NetworkClientInfo : : Iterate ( ) ) {
2008-05-30 20:20:26 +02:00
if ( ci - > client_playas = = company ) return true ;
}
return false ;
}
2009-01-13 12:46:29 +01:00
2010-10-15 21:35:08 +02:00
/**
2018-10-28 03:17:36 +01:00
* Get the name of the client , if the user did not send it yet , Client ID is used .
2010-10-15 21:35:08 +02:00
* @ param client_name The variable to write the name to .
2014-04-23 22:44:42 +02:00
* @ param last The pointer to the last element of the destination buffer
2010-10-15 21:35:08 +02:00
*/
2021-06-14 16:09:50 +02:00
std : : string ServerNetworkGameSocketHandler : : GetClientName ( ) const
2010-10-15 21:35:08 +02:00
{
const NetworkClientInfo * ci = this - > GetInfo ( ) ;
2021-06-14 16:09:50 +02:00
if ( ci ! = nullptr & & ! ci - > client_name . empty ( ) ) return ci - > client_name ;
2010-10-15 21:35:08 +02:00
2021-06-14 16:09:50 +02:00
return fmt : : format ( " Client #{} " , this - > client_id ) ;
2010-10-15 21:35:08 +02:00
}
2011-04-22 17:57:05 +02:00
/**
* Print all the clients to the console
*/
void NetworkPrintClients ( )
{
2019-12-16 20:56:10 +01:00
for ( NetworkClientInfo * ci : NetworkClientInfo : : Iterate ( ) ) {
2012-02-12 22:17:32 +01:00
if ( _network_server ) {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Client #{} name: '{}' company: {} IP: {} " ,
2012-02-12 22:17:32 +01:00
ci - > client_id ,
2021-06-14 16:09:50 +02:00
ci - > client_name ,
2012-02-12 22:17:32 +01:00
ci - > client_playas + ( Company : : IsValidID ( ci - > client_playas ) ? 1 : 0 ) ,
ci - > client_id = = CLIENT_ID_SERVER ? " server " : NetworkClientSocket : : GetByClientID ( ci - > client_id ) - > GetClientIP ( ) ) ;
} else {
2021-06-12 21:31:57 +02:00
IConsolePrint ( CC_INFO , " Client #{} name: '{}' company: {} " ,
2012-02-12 22:17:32 +01:00
ci - > client_id ,
2021-06-14 16:09:50 +02:00
ci - > client_name ,
2012-02-12 22:17:32 +01:00
ci - > client_playas + ( Company : : IsValidID ( ci - > client_playas ) ? 1 : 0 ) ) ;
}
2011-04-22 17:57:05 +02:00
}
}
2014-05-11 14:52:21 +02:00
/**
* Perform all the server specific administration of a new company .
2019-04-10 23:07:06 +02:00
* @ param c The newly created company ; can ' t be nullptr .
* @ param ci The client information of the client that made the company ; can be nullptr .
2014-05-11 14:52:21 +02:00
*/
void NetworkServerNewCompany ( const Company * c , NetworkClientInfo * ci )
{
2019-04-10 23:07:06 +02:00
assert ( c ! = nullptr ) ;
2014-05-11 14:52:21 +02:00
if ( ! _network_server ) return ;
_network_company_states [ c - > index ] . months_empty = 0 ;
2021-05-02 08:27:06 +02:00
_network_company_states [ c - > index ] . password . clear ( ) ;
2014-05-11 14:52:21 +02:00
NetworkServerUpdateCompanyPassworded ( c - > index , false ) ;
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
2014-05-11 14:52:21 +02:00
ci - > client_playas = c - > index ;
NetworkUpdateClientInfo ( ci - > client_id ) ;
2021-11-28 17:37:04 +01:00
Command < CMD_RENAME_PRESIDENT > : : SendNet ( STR_NULL , c - > index , ci - > client_name ) ;
2014-05-11 14:52:21 +02:00
}
/* Announce new company on network. */
NetworkAdminCompanyInfo ( c , true ) ;
2014-05-25 21:01:30 +02:00
2019-04-10 23:07:06 +02:00
if ( ci ! = nullptr ) {
/* ci is nullptr when replaying, or for AIs. In neither case there is a client.
2014-05-25 21:01:30 +02:00
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 ) */
NetworkServerSendChat ( NETWORK_ACTION_COMPANY_NEW , DESTTYPE_BROADCAST , 0 , " " , ci - > client_id , c - > index + 1 ) ;
}
2014-05-11 14:52:21 +02:00
}