LCOV - code coverage report
Current view: top level - source/network - NetClient.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 11 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 25 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef NETCLIENT_H
      19             : #define NETCLIENT_H
      20             : 
      21             : #include "network/FSM.h"
      22             : #include "network/NetFileTransfer.h"
      23             : #include "network/NetHost.h"
      24             : #include "scriptinterface/Object.h"
      25             : 
      26             : #include "ps/CStr.h"
      27             : 
      28             : #include <ctime>
      29             : #include <deque>
      30             : #include <thread>
      31             : 
      32             : class CGame;
      33             : class CNetClientSession;
      34             : class CNetClientTurnManager;
      35             : class ScriptInterface;
      36             : 
      37             : typedef struct _ENetHost ENetHost;
      38             : 
      39             : // NetClient session FSM states
      40             : enum
      41             : {
      42             :     NCS_UNCONNECTED,
      43             :     NCS_CONNECT,
      44             :     NCS_HANDSHAKE,
      45             :     NCS_AUTHENTICATE,
      46             :     NCS_PREGAME,
      47             :     NCS_LOADING,
      48             :     NCS_JOIN_SYNCING,
      49             :     NCS_INGAME
      50             : };
      51             : 
      52             : /**
      53             :  * Network client.
      54             :  * This code is run by every player (including the host, if they are not
      55             :  * a dedicated server).
      56             :  * It provides an interface between the GUI, the network (via CNetClientSession),
      57             :  * and the game (via CGame and CNetClientTurnManager).
      58             :  */
      59             : class CNetClient : public CFsm
      60             : {
      61             :     NONCOPYABLE(CNetClient);
      62             : 
      63             :     friend class CNetFileReceiveTask_ClientRejoin;
      64             : 
      65             : public:
      66             :     /**
      67             :      * Construct a client associated with the given game object.
      68             :      * The game must exist for the lifetime of this object.
      69             :      */
      70             :     CNetClient(CGame* game);
      71             : 
      72             :     virtual ~CNetClient();
      73             : 
      74             :     /**
      75             :      * We assume that adding a tracing function that's only called
      76             :      * during GC is better for performance than using a
      77             :      * PersistentRooted<T> where each value needs to be added to
      78             :      * the root set.
      79             :      */
      80           0 :     static void Trace(JSTracer *trc, void *data)
      81             :     {
      82           0 :         reinterpret_cast<CNetClient*>(data)->TraceMember(trc);
      83           0 :     }
      84             : 
      85             :     void TraceMember(JSTracer *trc);
      86             : 
      87             :     /**
      88             :      * Set the user's name that will be displayed to all players.
      89             :      * This must not be called after the connection setup.
      90             :      */
      91             :     void SetUserName(const CStrW& username);
      92             : 
      93             :     /**
      94             :      * Store the JID of the host.
      95             :      * This is needed for the secure lobby authentication.
      96             :      */
      97             :     void SetHostJID(const CStr& jid);
      98             : 
      99             :     void SetControllerSecret(const std::string& secret);
     100             : 
     101           0 :     bool IsController() const { return m_IsController; }
     102             : 
     103             :     /**
     104             :      * Set the game password.
     105             :      * Must be called after SetUserName, as that is used to hash further.
     106             :      */
     107             :     void SetGamePassword(const CStr& hashedPassword);
     108             : 
     109             :     /**
     110             :      * Returns the GUID of the local client.
     111             :      * Used for distinguishing observers.
     112             :      */
     113           0 :     CStr GetGUID() const { return m_GUID; }
     114             : 
     115             :     /**
     116             :      * Set connection data to the remote networked server.
     117             :      * @param address IP address or host name to connect to
     118             :      */
     119             :     void SetupServerData(CStr address, u16 port, bool stun);
     120             : 
     121             :     /**
     122             :      * Set up a connection to the remote networked server.
     123             :      * Must call SetupServerData first.
     124             :      * @return true on success, false on connection failure
     125             :      */
     126             :     bool SetupConnection(ENetHost* enetClient);
     127             : 
     128             :     /**
     129             :      * Request connection information over the lobby.
     130             :      */
     131             :     void SetupConnectionViaLobby();
     132             : 
     133             :     /**
     134             :      * Connect to the remote networked server using lobby.
     135             :      * Push netstatus messages on failure.
     136             :      * @param localNetwork - if true, assume we are trying to connect on the local network.
     137             :      * @return true on success, false on connection failure
     138             :      */
     139             :     bool TryToConnect(const CStr& hostJID, bool localNetwork);
     140             : 
     141             :     /**
     142             :      * Destroy the connection to the server.
     143             :      * This client probably cannot be used again.
     144             :      */
     145             :     void DestroyConnection();
     146             : 
     147             :     /**
     148             :      * Poll the connection for messages from the server and process them, and send
     149             :      * any queued messages.
     150             :      * This must be called frequently (i.e. once per frame).
     151             :      */
     152             :     void Poll();
     153             : 
     154             :     /**
     155             :      * Locally triggers a GUI message if the connection to the server is being lost or has bad latency.
     156             :      */
     157             :     void CheckServerConnection();
     158             : 
     159             :     /**
     160             :      * Retrieves the next queued GUI message, and removes it from the queue.
     161             :      * The returned value is in the GetScriptInterface() JS context.
     162             :      *
     163             :      * This is the only mechanism for the networking code to send messages to
     164             :      * the GUI - it is pull-based (instead of push) so the engine code does not
     165             :      * need to know anything about the code structure of the GUI scripts.
     166             :      *
     167             :      * The structure of the messages is <code>{ "type": "...", ... }</code>.
     168             :      * The exact types and associated data are not specified anywhere - the
     169             :      * implementation and GUI scripts must make the same assumptions.
     170             :      *
     171             :      * @return next message, or the value 'undefined' if the queue is empty
     172             :      */
     173             :     void GuiPoll(JS::MutableHandleValue);
     174             : 
     175             :     /**
     176             :      * Add a message to the queue, to be read by GuiPoll.
     177             :      * The script value must be in the GetScriptInterface() JS context.
     178             :      */
     179             :     template<typename... Args>
     180           0 :     void PushGuiMessage(Args const&... args)
     181             :     {
     182           0 :         ScriptRequest rq(GetScriptInterface());
     183             : 
     184           0 :         JS::RootedValue message(rq.cx);
     185           0 :         Script::CreateObject(rq, &message, args...);
     186           0 :         m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message));
     187           0 :     }
     188             : 
     189             :     /**
     190             :      * Return a concatenation of all messages in the GUI queue,
     191             :      * for test cases to easily verify the queue contents.
     192             :      */
     193             :     std::string TestReadGuiMessages();
     194             : 
     195             :     /**
     196             :      * Get the script interface associated with this network client,
     197             :      * which is equivalent to the one used by the CGame in the constructor.
     198             :      */
     199             :     const ScriptInterface& GetScriptInterface();
     200             : 
     201             :     /**
     202             :      * Send a message to the server.
     203             :      * @param message message to send
     204             :      * @return true on success
     205             :      */
     206             :     bool SendMessage(const CNetMessage* message);
     207             : 
     208             :     /**
     209             :      * Call when the network connection has been successfully initiated.
     210             :      */
     211             :     void HandleConnect();
     212             : 
     213             :     /**
     214             :      * Call when the network connection has been lost.
     215             :      */
     216             :     void HandleDisconnect(u32 reason);
     217             : 
     218             :     /**
     219             :      * Call when a message has been received from the network.
     220             :      */
     221             :     bool HandleMessage(CNetMessage* message);
     222             : 
     223             :     /**
     224             :      * Call when the game has started and all data files have been loaded,
     225             :      * to signal to the server that we are ready to begin the game.
     226             :      */
     227             :     void LoadFinished();
     228             : 
     229             :     void SendGameSetupMessage(JS::MutableHandleValue attrs, const ScriptInterface& scriptInterface);
     230             : 
     231             :     void SendAssignPlayerMessage(const int playerID, const CStr& guid);
     232             : 
     233             :     void SendChatMessage(const std::wstring& text);
     234             : 
     235             :     void SendReadyMessage(const int status);
     236             : 
     237             :     void SendClearAllReadyMessage();
     238             : 
     239             :     void SendStartGameMessage(const CStr& initAttribs);
     240             : 
     241             :     /**
     242             :      * Call when the client has rejoined a running match and finished
     243             :      * the loading screen.
     244             :      */
     245             :     void SendRejoinedMessage();
     246             : 
     247             :     /**
     248             :      * Call to kick/ban a client
     249             :      */
     250             :     void SendKickPlayerMessage(const CStrW& playerName, bool ban);
     251             : 
     252             :     /**
     253             :      * Call when the client has paused or unpaused the game.
     254             :      */
     255             :     void SendPausedMessage(bool pause);
     256             : 
     257             :     /**
     258             :      * @return Whether the NetClient is shutting down.
     259             :      */
     260             :     bool ShouldShutdown() const;
     261             : 
     262             :     /**
     263             :      * Called when fetching connection data from the host failed, to inform JS code.
     264             :      */
     265             :     void HandleGetServerDataFailed(const CStr& error);
     266             : private:
     267             : 
     268             :     void SendAuthenticateMessage();
     269             : 
     270             :     // Net message / FSM transition handlers
     271             :     static bool OnConnect(void* context, CFsmEvent* event);
     272             :     static bool OnHandshake(void* context, CFsmEvent* event);
     273             :     static bool OnHandshakeResponse(void* context, CFsmEvent* event);
     274             :     static bool OnAuthenticateRequest(void* context, CFsmEvent* event);
     275             :     static bool OnAuthenticate(void* context, CFsmEvent* event);
     276             :     static bool OnChat(void* context, CFsmEvent* event);
     277             :     static bool OnReady(void* context, CFsmEvent* event);
     278             :     static bool OnGameSetup(void* context, CFsmEvent* event);
     279             :     static bool OnPlayerAssignment(void* context, CFsmEvent* event);
     280             :     static bool OnInGame(void* context, CFsmEvent* event);
     281             :     static bool OnGameStart(void* context, CFsmEvent* event);
     282             :     static bool OnJoinSyncStart(void* context, CFsmEvent* event);
     283             :     static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
     284             :     static bool OnRejoined(void* context, CFsmEvent* event);
     285             :     static bool OnKicked(void* context, CFsmEvent* event);
     286             :     static bool OnClientTimeout(void* context, CFsmEvent* event);
     287             :     static bool OnClientPerformance(void* context, CFsmEvent* event);
     288             :     static bool OnClientsLoading(void* context, CFsmEvent* event);
     289             :     static bool OnClientPaused(void* context, CFsmEvent* event);
     290             :     static bool OnLoadedGame(void* context, CFsmEvent* event);
     291             : 
     292             :     /**
     293             :      * Take ownership of a session object, and use it for all network communication.
     294             :      */
     295             :     void SetAndOwnSession(CNetClientSession* session);
     296             : 
     297             :     /**
     298             :      * Push a message onto the GUI queue listing the current player assignments.
     299             :      */
     300             :     void PostPlayerAssignmentsToScript();
     301             : 
     302             :     CGame *m_Game;
     303             :     CStrW m_UserName;
     304             : 
     305             :     CStr m_HostJID;
     306             :     CStr m_ServerAddress;
     307             :     u16 m_ServerPort;
     308             :     bool m_UseSTUN;
     309             : 
     310             :     /**
     311             :      * Password to join the game.
     312             :      */
     313             :     CStr m_Password;
     314             : 
     315             :     /// The 'secret' used to identify the controller of the game.
     316             :     std::string m_ControllerSecret;
     317             : 
     318             :     /// Note that this is just a "gui hint" with no actual impact on being controller.
     319             :     bool m_IsController = false;
     320             : 
     321             :     /// Current network session (or NULL if not connected)
     322             :     CNetClientSession* m_Session;
     323             : 
     324             :     std::thread m_PollingThread;
     325             : 
     326             :     /// Turn manager associated with the current game (or NULL if we haven't started the game yet)
     327             :     CNetClientTurnManager* m_ClientTurnManager;
     328             : 
     329             :     /// Unique-per-game identifier of this client, used to identify the sender of simulation commands
     330             :     u32 m_HostID;
     331             : 
     332             :     /// True if the player is currently rejoining or has already rejoined the game.
     333             :     bool m_Rejoin;
     334             : 
     335             :     /// Latest copy of player assignments heard from the server
     336             :     PlayerAssignmentMap m_PlayerAssignments;
     337             : 
     338             :     /// Globally unique identifier to distinguish users beyond the lifetime of a single network session
     339             :     CStr m_GUID;
     340             : 
     341             :     /// Queue of messages for GuiPoll
     342             :     std::deque<JS::Heap<JS::Value>> m_GuiMessageQueue;
     343             : 
     344             :     /// Serialized game state received when joining an in-progress game
     345             :     std::string m_JoinSyncBuffer;
     346             : 
     347             :     /// Time when the server was last checked for timeouts and bad latency
     348             :     std::time_t m_LastConnectionCheck;
     349             : };
     350             : 
     351             : /// Global network client for the standard game
     352             : extern CNetClient *g_NetClient;
     353             : 
     354             : #endif  // NETCLIENT_H

Generated by: LCOV version 1.13