X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fclientiface.h;h=5335fa6442ac601066bb27cc8c65adbc039492b1;hb=5f1cd555cd9d1c64426e173b30b5b792d211c835;hp=a2315b3bd96d0d88aad95bfcdf0672e58012fcc7;hpb=e258675eabc874d31bc9c6cf49e4bbc1f7f3f417;p=oweals%2Fminetest.git diff --git a/src/clientiface.h b/src/clientiface.h index a2315b3bd..5335fa644 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -16,48 +16,186 @@ You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _CLIENTIFACE_H_ -#define _CLIENTIFACE_H_ + +#pragma once #include "irr_v3d.h" // for irrlicht datatypes #include "constants.h" #include "serialization.h" // for SER_FMT_VER_INVALID -#include "jthread/jmutex.h" +#include "network/networkpacket.h" +#include "network/networkprotocol.h" +#include "porting.h" #include #include -#include #include +#include class MapBlock; class ServerEnvironment; class EmergeManager; +/* + * State Transitions + + Start + (peer connect) + | + v + /-----------------\ + | | + | Created | + | | + \-----------------/ + | depending of the incoming packet + ---------------------------------------- + v + +-----------------------------+ + |IN: | + | TOSERVER_INIT | + +-----------------------------+ + | invalid playername + | or denied by mod + v + +-----------------------------+ + |OUT: | + | TOCLIENT_HELLO | + +-----------------------------+ + | + | + 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 | | + \-----------------/ | | | + | +-----------------------------+ | + | ^ | | + | ----------------------------- | + v v ++-----------------------------+ --------------------------------+ +|IN: | | ^ +| TOSERVER_CLIENT_READY | v | ++-----------------------------+ +------------------------+ | + | |OUT: | | + v | TOCLIENT_ACCESS_DENIED | | ++-----------------------------+ +------------------------+ | +|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 }; /* @@ -67,7 +205,7 @@ enum ClientStateEvent */ struct PrioritySortedBlockTransfer { - PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id) + PrioritySortedBlockTransfer(float a_priority, const v3s16 &a_pos, session_t a_peer_id) { priority = a_priority; pos = a_pos; @@ -79,7 +217,7 @@ struct PrioritySortedBlockTransfer } float priority; v3s16 pos; - u16 peer_id; + session_t peer_id; }; class RemoteClient @@ -89,30 +227,27 @@ public: // NOTE: If client is made allowed to exist while peer doesn't, // this has to be set to 0 when there is no peer. // Also, the client must be moved to some other container. - u16 peer_id; + session_t peer_id = PEER_ID_INEXISTENT; // The serialization version to use with the client - u8 serialization_version; + u8 serialization_version = SER_FMT_VER_INVALID; // - u16 net_proto_version; - - RemoteClient(): - peer_id(PEER_ID_INEXISTENT), - serialization_version(SER_FMT_VER_INVALID), - net_proto_version(0), - m_time_from_building(9999), - m_pending_serialization_version(SER_FMT_VER_INVALID), - m_state(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("") - { - } - ~RemoteClient() - { - } + u16 net_proto_version = 0; + + /* Authentication information */ + std::string enc_pwd = ""; + bool create_player_on_auth_success = false; + AuthMechanism chosen_mech = AUTH_MECHANISM_NONE; + void *auth_data = nullptr; + u32 allowed_auth_mechs = 0; + u32 allowed_sudo_mechs = 0; + + bool isSudoMechAllowed(AuthMechanism mech) + { return allowed_sudo_mechs & mech; } + bool isMechAllowed(AuthMechanism mech) + { return allowed_auth_mechs & mech; } + + RemoteClient(); + ~RemoteClient() = default; /* Finds block that should be sent next to the client. @@ -129,9 +264,19 @@ public: void SetBlockNotSent(v3s16 p); void SetBlocksNotSent(std::map &blocks); - s32 SendingCount() + /** + * 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); + + u32 getSendingCount() const { return m_blocks_sending.size(); } + + bool isBlockSent(v3s16 p) const { - return m_blocks_sending.size(); + return m_blocks_sent.find(p) != m_blocks_sent.end(); } // Increments timeouts and removes timed-out blocks from list @@ -151,22 +296,18 @@ public: } // Time from last placing or removing blocks - float m_time_from_building; + float m_time_from_building = 9999; /* List of active objects that the client knows of. - Value is dummy. */ std::set 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); @@ -175,15 +316,34 @@ public: 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 */ + u64 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; + u8 m_pending_serialization_version = SER_FMT_VER_INVALID; /* current state of client */ - ClientState m_state; + ClientState m_state = CS_Created; /* Blocks that have been sent to client. @@ -191,13 +351,20 @@ private: - 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 m_blocks_sent; - s16 m_nearest_unsent_d; + s16 m_nearest_unsent_d = 0; v3s16 m_last_center; - float m_nearest_unsent_reset_timer; + float m_nearest_unsent_reset_timer = 0.0f; + + const u16 m_max_simul_sends; + const float m_min_time_from_building; + const s16 m_max_send_distance; + const s16 m_block_optimize_distance; + const s16 m_max_gen_distance; + const bool m_occ_cull; /* Blocks that are currently on the line. @@ -209,6 +376,16 @@ private: */ std::map 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 m_blocks_modified; + /* Count of excess GotBlocks(). There is an excess amount because the client sometimes @@ -216,91 +393,123 @@ private: and the client then sends two GOTBLOCKs. This is resetted by PrintInfo() */ - u32 m_excess_gotblocks; + u32 m_excess_gotblocks = 0; // CPU usage optimization - u32 m_nothing_to_send_counter; - float m_nothing_to_send_pause_timer; - std::string m_name; + float m_nothing_to_send_pause_timer = 0.0f; + + /* + name of player using this client + */ + std::string m_name = ""; + + /* + client information + */ + u8 m_version_major = 0; + u8 m_version_minor = 0; + u8 m_version_patch = 0; + + std::string m_full_version = "unknown"; + + u16 m_deployed_compression = 0; + + /* + time this client was created + */ + const u64 m_connection_time = porting::getTimeS(); }; +typedef std::unordered_map RemoteClientMap; + class ClientInterface { public: friend class Server; - ClientInterface(con::Connection* con); + ClientInterface(const std::shared_ptr &con); ~ClientInterface(); /* run sync step */ void step(float dtime); /* get list of active client id's */ - std::list getClientIDs(ClientState min_state=Active); + std::vector getClientIDs(ClientState min_state=CS_Active); + + /* mark block as not sent to active client sessions */ + void markBlockposAsNotSent(const v3s16 &pos); + + /* verify is server user limit was reached */ + bool isUserLimitReached(); /* get list of client player names */ - std::vector getPlayerNames(); + const std::vector &getPlayerNames() const { return m_clients_names; } /* send message to client */ - void send(u16 peer_id, u8 channelnum, SharedBuffer data, bool reliable); + void send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable); /* send to all clients */ - void sendToAll(u16 channelnum, SharedBuffer data, bool reliable); + void sendToAll(NetworkPacket *pkt); + void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver); /* delete a client */ - void DeleteClient(u16 peer_id); + void DeleteClient(session_t peer_id); /* create client */ - void CreateClient(u16 peer_id); + void CreateClient(session_t peer_id); /* get a client by peer_id */ - RemoteClient* getClientNoEx(u16 peer_id, ClientState state_min=Active); + RemoteClient *getClientNoEx(session_t 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(session_t peer_id, ClientState state_min = CS_Active); /* get state of client by id*/ - ClientState getClientState(u16 peer_id); + ClientState getClientState(session_t peer_id); /* set client playername */ - void setPlayerName(u16 peer_id,std::string name); + void setPlayerName(session_t peer_id, const std::string &name); /* get protocol version of client */ - u16 getProtocolVersion(u16 peer_id); + u16 getProtocolVersion(session_t peer_id); + + /* set client version */ + void setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch, + const std::string &full); /* event to update client state */ - void event(u16 peer_id, ClientStateEvent event); + void event(session_t 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& getClientList() - { return m_clients; } + RemoteClientMap& getClientList() { return m_clients; } private: /* update internal player list */ void UpdatePlayerList(); // Connection - con::Connection* m_con; - JMutex m_clients_mutex; + std::shared_ptr m_con; + std::mutex m_clients_mutex; // Connected clients (behind the con mutex) - std::map m_clients; + RemoteClientMap m_clients; std::vector m_clients_names; //for announcing masterserver // Environment ServerEnvironment *m_env; - JMutex m_env_mutex; float m_print_info_timer; -}; -#endif + static const char *statenames[]; +};