#include "constants.h"
#include "serialization.h" // for SER_FMT_VER_INVALID
-#include "jthread/jmutex.h"
+#include "threading/mutex.h"
+#include "network/networkpacket.h"
+#include "util/cpp11_container.h"
+#include "porting.h"
#include <list>
#include <vector>
-#include <map>
#include <set>
class MapBlock;
class ServerEnvironment;
class EmergeManager;
+/*
+ * State Transitions
+
+ Start
+ (peer connect)
+ |
+ v
+ /-----------------\
+ | |
+ | Created |
+ | |
+ \-----------------/
+ | depending of the incoming packet
+ +---------------------------------------
+ v v
++-----------------------------+ +-----------------------------+
+|IN: | |IN: |
+| TOSERVER_INIT_LEGACY |----- | TOSERVER_INIT | invalid playername,
++-----------------------------+ | +-----------------------------+ password (for _LEGACY),
+ | | | or denied by mod
+ | Auth ok -------------------+---------------------------------
+ v v |
++-----------------------------+ +-----------------------------+ |
+|OUT: | |OUT: | |
+| TOCLIENT_INIT_LEGACY | | TOCLIENT_HELLO | |
++-----------------------------+ +-----------------------------+ |
+ | | |
+ | | |
+ v v |
+ /-----------------\ /-----------------\ |
+ | | | | |
+ | AwaitingInit2 |<--------- | HelloSent | |
+ | | | | | |
+ \-----------------/ | \-----------------/ |
+ | | | |
++-----------------------------+ | *-----------------------------* Auth fails |
+|IN: | | |Authentication, depending on |-----------------+
+| TOSERVER_INIT2 | | | packet sent by client | |
++-----------------------------+ | *-----------------------------* |
+ | | | |
+ | | | Authentication |
+ v | | successful |
+ /-----------------\ | v |
+ | | | +-----------------------------+ |
+ | InitDone | | |OUT: | |
+ | | | | TOCLIENT_AUTH_ACCEPT | |
+ \-----------------/ | +-----------------------------+ |
+ | | | |
++-----------------------------+ --------------------- |
+|OUT: | |
+| TOCLIENT_MOVEMENT | |
+| TOCLIENT_ITEMDEF | |
+| TOCLIENT_NODEDEF | |
+| TOCLIENT_ANNOUNCE_MEDIA | |
+| TOCLIENT_DETACHED_INVENTORY | |
+| TOCLIENT_TIME_OF_DAY | |
++-----------------------------+ |
+ | |
+ | |
+ | ----------------------------- |
+ v | | |
+ /-----------------\ v |
+ | | +-----------------------------+ |
+ | DefinitionsSent | |IN: | |
+ | | | TOSERVER_REQUEST_MEDIA | |
+ \-----------------/ | TOSERVER_RECEIVED_MEDIA | |
+ | +-----------------------------+ |
+ | ^ | |
+ | ----------------------------- |
+ v |
++-----------------------------+ --------------------------------+
+|IN: | | |
+| TOSERVER_CLIENT_READY | v |
++-----------------------------+ +-------------------------------+ |
+ | |OUT: | |
+ v | TOCLIENT_ACCESS_DENIED_LEGAGY | |
++-----------------------------+ +-------------------------------+ |
+|OUT: | | |
+| TOCLIENT_MOVE_PLAYER | v |
+| TOCLIENT_PRIVILEGES | /-----------------\ |
+| TOCLIENT_INVENTORY_FORMSPEC | | | |
+| UpdateCrafting | | Denied | |
+| TOCLIENT_INVENTORY | | | |
+| TOCLIENT_HP (opt) | \-----------------/ |
+| TOCLIENT_BREATH | |
+| TOCLIENT_DEATHSCREEN | |
++-----------------------------+ |
+ | |
+ v |
+ /-----------------\ async mod action (ban, kick) |
+ | |---------------------------------------------------------------
+ ---->| Active |
+ | | |----------------------------------------------
+ | \-----------------/ timeout v
+ | | | +-----------------------------+
+ | | | |OUT: |
+ | | | | TOCLIENT_DISCONNECT |
+ | | | +-----------------------------+
+ | | | |
+ | | v v
+ | | +-----------------------------+ /-----------------\
+ | | |IN: | | |
+ | | | TOSERVER_DISCONNECT |------------------->| Disconnecting |
+ | | +-----------------------------+ | |
+ | | \-----------------/
+ | | any auth packet which was
+ | | allowed in TOCLIENT_AUTH_ACCEPT
+ | v
+ | *-----------------------------* Auth +-------------------------------+
+ | |Authentication, depending on | succeeds |OUT: |
+ | | packet sent by client |---------->| TOCLIENT_ACCEPT_SUDO_MODE |
+ | *-----------------------------* +-------------------------------+
+ | | |
+ | | Auth fails /-----------------\
+ | v | |
+ | +-------------------------------+ | SudoMode |
+ | |OUT: | | |
+ | | TOCLIENT_DENY_SUDO_MODE | \-----------------/
+ | +-------------------------------+ |
+ | | v
+ | | +-----------------------------+
+ | | sets password accordingly |IN: |
+ -------------------+-------------------------------| TOSERVER_FIRST_SRP |
+ +-----------------------------+
+
+*/
namespace con {
class Connection;
}
+
+// Also make sure to update the ClientInterface::statenames
+// array when modifying these enums
+
enum ClientState
{
- Invalid,
- Disconnecting,
- Denied,
- Created,
- InitSent,
- InitDone,
- DefinitionsSent,
- Active
+ CS_Invalid,
+ CS_Disconnecting,
+ CS_Denied,
+ CS_Created,
+ CS_AwaitingInit2,
+ CS_HelloSent,
+ CS_InitDone,
+ CS_DefinitionsSent,
+ CS_Active,
+ CS_SudoMode
};
enum ClientStateEvent
{
- Init,
- GotInit2,
- SetDenied,
- SetDefinitionsSent,
- SetMediaSent,
- Disconnect
+ CSE_Hello,
+ CSE_AuthAccept,
+ CSE_InitLegacy,
+ CSE_GotInit2,
+ CSE_SetDenied,
+ CSE_SetDefinitionsSent,
+ CSE_SetClientReady,
+ CSE_SudoSuccess,
+ CSE_SudoLeave,
+ CSE_Disconnect
};
/*
//
u16 net_proto_version;
+ /* Authentication information */
+ std::string enc_pwd;
+ bool create_player_on_auth_success;
+ AuthMechanism chosen_mech;
+ void * auth_data;
+ u32 allowed_auth_mechs;
+ u32 allowed_sudo_mechs;
+
+ bool isSudoMechAllowed(AuthMechanism mech)
+ { return allowed_sudo_mechs & mech; }
+ bool isMechAllowed(AuthMechanism mech)
+ { return allowed_auth_mechs & mech; }
+
RemoteClient():
peer_id(PEER_ID_INEXISTENT),
serialization_version(SER_FMT_VER_INVALID),
net_proto_version(0),
+ create_player_on_auth_success(false),
+ chosen_mech(AUTH_MECHANISM_NONE),
+ auth_data(NULL),
m_time_from_building(9999),
m_pending_serialization_version(SER_FMT_VER_INVALID),
- m_state(Created),
+ m_state(CS_Created),
m_nearest_unsent_d(0),
m_nearest_unsent_reset_timer(0.0),
m_excess_gotblocks(0),
- m_nothing_to_send_counter(0),
m_nothing_to_send_pause_timer(0.0),
- m_name("")
+ m_name(""),
+ m_version_major(0),
+ m_version_minor(0),
+ m_version_patch(0),
+ m_full_version("unknown"),
+ m_deployed_compression(0),
+ m_connection_time(porting::getTime(PRECISION_SECONDS))
{
}
~RemoteClient()
void SetBlockNotSent(v3s16 p);
void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
+ /**
+ * tell client about this block being modified right now.
+ * this information is required to requeue the block in case it's "on wire"
+ * while modification is processed by server
+ * @param p position of modified block
+ */
+ void ResendBlockIfOnWire(v3s16 p);
+
s32 SendingCount()
{
return m_blocks_sending.size();
/*
List of active objects that the client knows of.
- Value is dummy.
*/
std::set<u16> m_known_objects;
- ClientState getState()
- { return m_state; }
+ ClientState getState() const { return m_state; }
- std::string getName()
- { return m_name; }
+ std::string getName() const { return m_name; }
- void setName(std::string name)
- { m_name = name; }
+ void setName(const std::string &name) { m_name = name; }
/* update internal client state */
void notifyEvent(ClientStateEvent event);
void setPendingSerializationVersion(u8 version)
{ m_pending_serialization_version = version; }
+ void setDeployedCompressionMode(u16 byteFlag)
+ { m_deployed_compression = byteFlag; }
+
void confirmSerializationVersion()
{ serialization_version = m_pending_serialization_version; }
+ /* get uptime */
+ u32 uptime() const;
+
+ /* set version information */
+ void setVersionInfo(u8 major, u8 minor, u8 patch, const std::string &full)
+ {
+ m_version_major = major;
+ m_version_minor = minor;
+ m_version_patch = patch;
+ m_full_version = full;
+ }
+
+ /* read version information */
+ u8 getMajor() const { return m_version_major; }
+ u8 getMinor() const { return m_version_minor; }
+ u8 getPatch() const { return m_version_patch; }
private:
// Version is stored in here after INIT before INIT2
u8 m_pending_serialization_version;
- A block is cleared from here when client says it has
deleted it from it's memory
- Key is position, value is dummy.
+ List of block positions.
No MapBlock* is stored here because the blocks can get deleted.
*/
std::set<v3s16> m_blocks_sent;
*/
std::map<v3s16, float> m_blocks_sending;
+ /*
+ Blocks that have been modified since last sending them.
+ These blocks will not be marked as sent, even if the
+ client reports it has received them to account for blocks
+ that are being modified while on the line.
+
+ List of block positions.
+ */
+ std::set<v3s16> m_blocks_modified;
+
/*
Count of excess GotBlocks().
There is an excess amount because the client sometimes
u32 m_excess_gotblocks;
// CPU usage optimization
- u32 m_nothing_to_send_counter;
float m_nothing_to_send_pause_timer;
+
+ /*
+ name of player using this client
+ */
std::string m_name;
+
+ /*
+ client information
+ */
+ u8 m_version_major;
+ u8 m_version_minor;
+ u8 m_version_patch;
+
+ std::string m_full_version;
+
+ u16 m_deployed_compression;
+
+ /*
+ time this client was created
+ */
+ const u32 m_connection_time;
};
class ClientInterface {
void step(float dtime);
/* get list of active client id's */
- std::list<u16> getClientIDs(ClientState min_state=Active);
+ std::vector<u16> getClientIDs(ClientState min_state=CS_Active);
/* get list of client player names */
- std::vector<std::string> getPlayerNames();
+ const std::vector<std::string> &getPlayerNames() const { return m_clients_names; }
/* send message to client */
- void send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
+ void send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable);
/* send to all clients */
- void sendToAll(u16 channelnum, SharedBuffer<u8> data, bool reliable);
+ void sendToAll(NetworkPacket *pkt);
/* delete a client */
void DeleteClient(u16 peer_id);
void CreateClient(u16 peer_id);
/* get a client by peer_id */
- RemoteClient* getClientNoEx(u16 peer_id, ClientState state_min=Active);
+ RemoteClient* getClientNoEx(u16 peer_id, ClientState state_min=CS_Active);
/* get client by peer_id (make sure you have list lock before!*/
- RemoteClient* lockedGetClientNoEx(u16 peer_id, ClientState state_min=Active);
+ RemoteClient* lockedGetClientNoEx(u16 peer_id, ClientState state_min=CS_Active);
/* get state of client by id*/
ClientState getClientState(u16 peer_id);
/* get protocol version of client */
u16 getProtocolVersion(u16 peer_id);
+ /* set client version */
+ void setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full);
+
/* event to update client state */
void event(u16 peer_id, ClientStateEvent event);
- /* set environment */
- void setEnv(ServerEnvironment* env)
- { assert(m_env == 0); m_env = env; }
+ /* Set environment. Do not call this function if environment is already set */
+ void setEnv(ServerEnvironment *env)
+ {
+ assert(m_env == NULL); // pre-condition
+ m_env = env;
+ }
+
+ static std::string state2Name(ClientState state);
protected:
//TODO find way to avoid this functions
- void Lock()
- { m_clients_mutex.Lock(); }
- void Unlock()
- { m_clients_mutex.Unlock(); }
+ void lock() { m_clients_mutex.lock(); }
+ void unlock() { m_clients_mutex.unlock(); }
- std::map<u16, RemoteClient*>& getClientList()
- { return m_clients; }
+ UNORDERED_MAP<u16, RemoteClient*>& getClientList() { return m_clients; }
private:
/* update internal player list */
// Connection
con::Connection* m_con;
- JMutex m_clients_mutex;
+ Mutex m_clients_mutex;
// Connected clients (behind the con mutex)
- std::map<u16, RemoteClient*> m_clients;
+ UNORDERED_MAP<u16, RemoteClient*> m_clients;
std::vector<std::string> m_clients_names; //for announcing masterserver
// Environment
ServerEnvironment *m_env;
- JMutex m_env_mutex;
+ Mutex m_env_mutex;
float m_print_info_timer;
+
+ static const char *statenames[];
};
#endif