Pyrogenesis  trunk
NetServer.h
Go to the documentation of this file.
1 /* Copyright (C) 2017 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 NETSERVER_H
19 #define NETSERVER_H
20 
21 #include "NetFileTransfer.h"
22 #include "NetHost.h"
23 
24 #include "lib/config2.h"
25 #include "ps/ThreadUtil.h"
27 
28 #include <vector>
29 
30 class CNetServerSession;
32 class CFsmEvent;
33 class ScriptInterface;
34 class CPlayerAssignmentMessage;
35 class CNetStatsTable;
36 class CSimulationMessage;
37 
38 class CNetServerWorker;
39 
41 {
42  // We haven't opened the port yet, we're just setting some stuff up.
43  // The worker thread has not been started.
45 
46  // The server is open and accepting connections. This is the screen where
47  // rules are set up by the operator and where players join and select civs
48  // and stuff.
50 
51  // All the hosts are connected and are loading the game
53 
54  // The one with all the killing ;-)
56 
57  // The game is over and someone has won. Players might linger to chat or
58  // download the replay log.
60 };
61 
62 /**
63  * Server session representation of client state
64  */
66 {
67  // The client has disconnected or been disconnected
69 
70  // The client has just connected and we're waiting for its handshake message,
71  // to agree on the protocol version
73 
74  // The client has handshook and we're waiting for its authentication message,
75  // to find its name and check its password etc
77 
78  // The client has fully joined, and is in the pregame setup stage
79  // or is loading the game.
80  // Server must be in SERVER_STATE_PREGAME or SERVER_STATE_LOADING.
82 
83  // The client has authenticated but the game was already started,
84  // so it's synchronising with the game state from other clients
86 
87  // The client is running the game.
88  // Server must be in SERVER_STATE_LOADING or SERVER_STATE_INGAME.
90 };
91 
92 /**
93  * Network server interface. Handles all the coordination between players.
94  * One person runs this object, and every player (including the host) connects their CNetClient to it.
95  *
96  * The actual work is performed by CNetServerWorker in a separate thread.
97  */
99 {
101 public:
102  /**
103  * Construct a new network server.
104  * @param autostartPlayers if positive then StartGame will be called automatically
105  * once this many players are connected (intended for the command-line testing mode).
106  */
107  CNetServer(int autostartPlayers = -1);
108 
109  ~CNetServer();
110 
111  /**
112  * Begin listening for network connections.
113  * This function is synchronous (it won't return until the connection is established).
114  * @return true on success, false on error (e.g. port already in use)
115  */
116  bool SetupConnection(const u16 port);
117 
118  /**
119  * Call from the GUI to asynchronously notify all clients that they should start loading the game.
120  */
121  void StartGame();
122 
123  /**
124  * Call from the GUI to update the game setup attributes.
125  * This must be called at least once before starting the game.
126  * The changes will be asynchronously propagated to all clients.
127  * @param attrs game attributes, in the script context of scriptInterface
128  */
129  void UpdateGameAttributes(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface);
130 
131  /**
132  * Set the turn length to a fixed value.
133  * TODO: we should replace this with some adapative lag-dependent computation.
134  */
135  void SetTurnLength(u32 msecs);
136 
137 private:
139 };
140 
141 /**
142  * Network server worker thread.
143  * (This is run in a thread so that client/server communication is not delayed
144  * by the host player's framerate - the only delay should be the network latency.)
145  *
146  * Thread-safety:
147  * - SetupConnection and constructor/destructor must be called from the main thread.
148  * - The main thread may push commands onto the Queue members,
149  * while holding the m_WorkerMutex lock.
150  * - Public functions (SendMessage, Broadcast) must be called from the network
151  * server thread.
152  */
154 {
156 
157 public:
158  // Public functions for CNetSession/CNetServerTurnManager to use:
159 
160  /**
161  * Send a message to the given network peer.
162  */
163  bool SendMessage(ENetPeer* peer, const CNetMessage* message);
164 
165  /**
166  * Disconnects a player from gamesetup or session.
167  */
168  void KickPlayer(const CStrW& playerName, const bool ban);
169 
170  /**
171  * Send a message to all clients who match one of the given states.
172  */
173  bool Broadcast(const CNetMessage* message, const std::vector<NetServerSessionState>& targetStates);
174 
175 private:
176  friend class CNetServer;
178 
179  CNetServerWorker(int autostartPlayers);
180  ~CNetServerWorker();
181 
182  /**
183  * Begin listening for network connections.
184  * @return true on success, false on error (e.g. port already in use)
185  */
186  bool SetupConnection(const u16 port);
187 
188  /**
189  * Call from the GUI to update the player assignments.
190  * The given GUID will be (re)assigned to the given player ID.
191  * Any player currently using that ID will be unassigned.
192  * The changes will be propagated to all clients.
193  */
194  void AssignPlayer(int playerID, const CStr& guid);
195 
196  /**
197  * Call from the GUI to notify all clients that they should start loading the game.
198  */
199  void StartGame();
200 
201  /**
202  * Call from the GUI to update the game setup attributes.
203  * This must be called at least once before starting the game.
204  * The changes will be propagated to all clients.
205  * @param attrs game attributes, in the script context of GetScriptInterface()
206  */
207  void UpdateGameAttributes(JS::MutableHandleValue attrs);
208 
209  /**
210  * Make a player name 'nicer' by limiting the length and removing forbidden characters etc.
211  */
212  static CStrW SanitisePlayerName(const CStrW& original);
213 
214  /**
215  * Make a player name unique, if it matches any existing session's name.
216  */
217  CStrW DeduplicatePlayerName(const CStrW& original);
218 
219  /**
220  * Get the script context used for game attributes.
221  */
222  ScriptInterface& GetScriptInterface();
223 
224  /**
225  * Set the turn length to a fixed value.
226  * TODO: we should replace this with some adaptive lag-dependent computation.
227  */
228  void SetTurnLength(u32 msecs);
229 
230  void AddPlayer(const CStr& guid, const CStrW& name);
231  void RemovePlayer(const CStr& guid);
232  void SendPlayerAssignments();
233  void ClearAllPlayerReady();
234 
235  void SetupSession(CNetServerSession* session);
236  bool HandleConnect(CNetServerSession* session);
237 
238  void OnUserJoin(CNetServerSession* session);
239  void OnUserLeave(CNetServerSession* session);
240 
241  static bool OnClientHandshake(void* context, CFsmEvent* event);
242  static bool OnAuthenticate(void* context, CFsmEvent* event);
243  static bool OnInGame(void* context, CFsmEvent* event);
244  static bool OnChat(void* context, CFsmEvent* event);
245  static bool OnReady(void* context, CFsmEvent* event);
246  static bool OnClearAllReady(void* context, CFsmEvent* event);
247  static bool OnGameSetup(void* context, CFsmEvent* event);
248  static bool OnAssignPlayer(void* context, CFsmEvent* event);
249  static bool OnStartGame(void* context, CFsmEvent* event);
250  static bool OnLoadedGame(void* context, CFsmEvent* event);
251  static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
252  static bool OnRejoined(void* context, CFsmEvent* event);
253  static bool OnKickPlayer(void* context, CFsmEvent* event);
254  static bool OnDisconnect(void* context, CFsmEvent* event);
255  static bool OnClientPaused(void* context, CFsmEvent* event);
256 
257  /**
258  * Checks if all clients have finished loading.
259  * If so informs the clients about that and change the server state.
260  *
261  * Returns if all clients finished loading.
262  */
263  bool CheckGameLoadStatus(CNetServerSession* changedSession);
264 
265  void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message);
266 
267  void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session);
268 
269  /**
270  * Send a network warning if the connection to a client is being lost or has bad latency.
271  */
272  void CheckClientConnections();
273 
274  /**
275  * Internal script context for (de)serializing script messages,
276  * and for storing game attributes.
277  * (TODO: we shouldn't bother deserializing (except for debug printing of messages),
278  * we should just forward messages blindly and efficiently.)
279  */
281 
283 
284  /**
285  * Stores the most current game attributes.
286  */
287  JS::PersistentRootedValue m_GameAttributes;
288 
290 
292  std::vector<CNetServerSession*> m_Sessions;
293 
295 
297 
300 
301  std::vector<u32> m_BannedIPs;
302  std::vector<CStrW> m_BannedPlayers;
303 
304  /**
305  * Holds the GUIDs of all currently paused players.
306  */
307  std::vector<CStr> m_PausingPlayers;
308 
310 
312 
314 
315  /**
316  * A copy of all simulation commands received so far, indexed by
317  * turn number, to simplify support for rejoining etc.
318  * TODO: verify this doesn't use too much RAM.
319  */
320  std::vector<std::vector<CSimulationMessage>> m_SavedCommands;
321 
322  /**
323  * The latest copy of the simulation state, received from an existing
324  * client when a new client has asked to rejoin the game.
325  */
326  std::string m_JoinSyncFile;
327 
328  /**
329  * Time when the clients connections were last checked for timeouts and latency.
330  */
332 
333 private:
334  // Thread-related stuff:
335 
336 #if CONFIG2_MINIUPNPC
337  /**
338  * Try to find a UPnP root on the network and setup port forwarding.
339  */
340  static void* SetupUPnP(void*);
342 #endif
343 
344  static void* RunThread(void* data);
345  void Run();
346  bool RunStep();
347 
350 
351  bool m_Shutdown; // protected by m_WorkerMutex
352 
353  // Queues for messages sent by the game thread:
354  std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
355  std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
356  std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
357 };
358 
359 /// Global network server for the standard game
360 extern CNetServer *g_NetServer;
361 
362 #endif // NETSERVER_H
pthread_t m_WorkerThread
Definition: NetServer.h:348
ScriptInterface * m_ScriptInterface
Internal script context for (de)serializing script messages, and for storing game attributes...
Definition: NetServer.h:280
void StartGame()
Call from the GUI to asynchronously notify all clients that they should start loading the game...
Definition: NetServer.cpp:1466
std::map< CStr, PlayerAssignment > PlayerAssignmentMap
Definition: NetHost.h:54
std::vector< CStr > m_PausingPlayers
Holds the GUIDs of all currently paused players.
Definition: NetServer.h:307
CStr m_HostGUID
Definition: NetServer.h:313
std::vector< std::vector< CSimulationMessage > > m_SavedCommands
A copy of all simulation commands received so far, indexed by turn number, to simplify support for re...
Definition: NetServer.h:320
uint16_t u16
Definition: types.h:38
std::string m_JoinSyncFile
The latest copy of the simulation state, received from an existing client when a new client has asked...
Definition: NetServer.h:326
Represents a signal in the state machine that a change has occurred.
Definition: fsm.h:53
Async task for receiving the initial game state to be forwarded to another client that is rejoining a...
Definition: NetServer.cpp:79
std::vector< CStrW > m_BannedPlayers
Definition: NetServer.h:302
u32 m_NextHostID
Definition: NetServer.h:309
Definition: NetServer.h:55
Definition: NetServer.h:76
struct _ENetPeer ENetPeer
Definition: NetHost.h:30
A non-recursive mutual exclusion lock.
Definition: ThreadUtil.h:45
void UpdateGameAttributes(JS::MutableHandleValue attrs, ScriptInterface &scriptInterface)
Call from the GUI to update the game setup attributes.
Definition: NetServer.cpp:1472
NetServerState
Definition: NetServer.h:40
pthread_t m_UPnPThread
Definition: NetServer.h:341
std::vector< std::string > m_GameAttributesQueue
Definition: NetServer.h:355
CNetServer(int autostartPlayers=-1)
Construct a new network server.
Definition: NetServer.cpp:1451
Definition: NetServer.h:81
std::time_t m_LastConnectionCheck
Time when the clients connections were last checked for timeouts and latency.
Definition: NetServer.h:331
void SetTurnLength(u32 msecs)
Set the turn length to a fixed value.
Definition: NetServer.cpp:1482
JS::PersistentRootedValue m_GameAttributes
Stores the most current game attributes.
Definition: NetServer.h:287
uint32_t u32
Definition: types.h:39
Various declarations shared by networking code.
void ClearAllPlayerReady(ScriptInterface::CxPrivate *pCxPrivate)
Definition: ScriptFunctions.cpp:429
bool m_Shutdown
Definition: NetServer.h:351
~CNetServer()
Definition: NetServer.cpp:1456
ENetHost * m_Host
Definition: NetServer.h:291
NetServerSessionState
Server session representation of client state.
Definition: NetServer.h:65
NONCOPYABLE(CNetServer)
Network server interface.
Definition: NetServer.h:98
ENet connection statistics profiler table.
Definition: NetStats.h:36
std::vector< bool > m_StartGameQueue
Definition: NetServer.h:354
std::vector< u32 > m_TurnLengthQueue
Definition: NetServer.h:356
std::vector< CNetServerSession * > m_Sessions
Definition: NetServer.h:292
Definition: NetServer.h:89
The base class for all network messages exchanged within the game.
Definition: NetMessage.h:32
int m_AutostartPlayers
Definition: NetServer.h:289
void KickPlayer(ScriptInterface::CxPrivate *pCxPrivate, const CStrW &playerName, bool ban)
Definition: ScriptFunctions.cpp:402
Definition: NetServer.h:52
CNetServerWorker * m_Worker
Definition: NetServer.h:138
CNetStatsTable * m_Stats
Definition: NetServer.h:294
uintptr_t pthread_t
Definition: wpthread.h:63
CStrW m_WelcomeMessage
Definition: NetServer.h:299
struct _ENetHost ENetHost
Definition: NetHost.h:32
std::vector< u32 > m_BannedIPs
Definition: NetServer.h:301
NetServerState m_State
Definition: NetServer.h:296
Abstraction around a SpiderMonkey JSContext.
Definition: ScriptInterface.h:71
Definition: NetServer.h:44
Definition: NetServer.h:68
CStrW m_ServerName
Definition: NetServer.h:298
CNetServerTurnManager * m_ServerTurnManager
Definition: NetServer.h:311
PlayerAssignmentMap m_PlayerAssignments
Definition: NetServer.h:282
Definition: NetServer.h:59
Network server worker thread.
Definition: NetServer.h:153
The server&#39;s end of a network session.
Definition: NetSession.h:127
Definition: NetServer.h:85
bool SetupConnection(const u16 port)
Begin listening for network connections.
Definition: NetServer.cpp:1461
CMutex m_WorkerMutex
Definition: NetServer.h:349
The server-side counterpart to CNetClientTurnManager.
Definition: NetServerTurnManager.h:34
CNetServer * g_NetServer
Global network server for the standard game.
Definition: NetServer.cpp:64
Definition: NetServer.h:49
Special message type for simulation commands.
Definition: NetMessage.h:113
static Status Run(const Operation &op, const Parameters &p=Parameters(), const CompletedHook &completedHook=CompletedHook(), const IssueHook &issueHook=IssueHook())
Definition: io.h:233
Definition: NetServer.h:72