summaryrefslogtreecommitdiffstats
path: root/src/Server.h
blob: aab47987f700c8787f44e855fb15ee53141f1c87 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

// cServer.h

// Interfaces to the cServer object representing the network server





#pragma once

#include "OSSupport/SocketThreads.h"
#include "OSSupport/ListenThread.h"

#include "RCONServer.h"

#ifdef _MSC_VER
	#pragma warning(push)
	#pragma warning(disable:4127)
	#pragma warning(disable:4244)
	#pragma warning(disable:4231)
	#pragma warning(disable:4189)
	#pragma warning(disable:4702)
#endif

#include "PolarSSL++/RsaPrivateKey.h"

#ifdef _MSC_VER
	#pragma warning(pop)
#endif





// fwd:
class cPlayer;
class cClientHandle;
class cIniFile;
class cCommandOutputCallback;

typedef std::list<cClientHandle *> cClientHandleList;

namespace Json
{
	class Value;
}





class cServer  // tolua_export
	: public cListenThread::cCallback
{        // tolua_export
public:  // tolua_export

	virtual ~cServer() {}
	bool InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth);

	// tolua_begin
	
	const AString & GetDescription(void) const {return m_Description; }

	// Player counts:
	int  GetMaxPlayers(void) const { return m_MaxPlayers; }
	int  GetNumPlayers(void) const;
	void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
	
	/** Check if the player is queued to be transferred to a World.
	Returns true is Player is found in queue. */
	bool IsPlayerInQueue(AString a_Username);
	
	/** Can login more than once with same username.
	Returns false if it is not allowed, true otherwise. */
	bool DoesAllowMultiLogin(void) { return m_bAllowMultiLogin; }
	
	// Hardcore mode or not:
	bool IsHardcore(void) const { return m_bIsHardcore; }

	// tolua_end

	bool Start(void);

	bool Command(cClientHandle & a_Client, AString & a_Cmd);
	
	/** Executes the console command, sends output through the specified callback */
	void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
	
	/** Lists all available console commands and their helpstrings */
	void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output);

	/** Binds the built-in console commands with the plugin manager */
	static void BindBuiltInConsoleCommands(void);
	
	void Shutdown(void);

	void KickUser(int a_ClientID, const AString & a_Reason);
	
	/** Authenticates the specified user, called by cAuthenticator */
	void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);

	const AString & GetServerID(void) const { return m_ServerID; }  // tolua_export
	
	/** Called by cClientHandle's destructor; stop m_SocketThreads from calling back into a_Client */
	void ClientDestroying(const cClientHandle * a_Client);
	
	/** Notifies m_SocketThreads that client has something to be written */
	void NotifyClientWrite(const cClientHandle * a_Client);
	
	void WriteToClient(const cClientHandle * a_Client, const AString & a_Data);  // Queues outgoing data for the client through m_SocketThreads
	
	void RemoveClient(const cClientHandle * a_Client);  // Removes the clienthandle from m_SocketThreads
	
	/** Don't tick a_Client anymore, it will be ticked from its cPlayer instead */
	void ClientMovedToWorld(const cClientHandle * a_Client);
	
	/** Notifies the server that a player was created; the server uses this to adjust the number of players */
	void PlayerCreated(const cPlayer * a_Player);
	
	/** Notifies the server that a player is being destroyed; the server uses this to adjust the number of players */
	void PlayerDestroying(const cPlayer * a_Player);

	/** Returns base64 encoded favicon data (obtained from favicon.png) */
	const AString & GetFaviconData(void) const { return m_FaviconData; }
	
	cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
	const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
	
	/** Returns true if authentication has been turned on in server settings. */
	bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }  // tolua_export
	
	/** Returns true if offline UUIDs should be used to load data for players whose normal UUIDs cannot be found.
	Loaded from the settings.ini [PlayerData].LoadOfflinePlayerData setting. */
	bool ShouldLoadOfflinePlayerData(void) const { return m_ShouldLoadOfflinePlayerData; }
	
	/** Returns true if old-style playernames should be used to load data for players whose regular datafiles cannot be found.
	This allows a seamless transition from name-based to UUID-based player storage.
	Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
	bool ShouldLoadNamedPlayerData(void) const { return m_ShouldLoadNamedPlayerData; }
	
	/** Returns true if BungeeCord logins (that specify the player's UUID) are allowed.
	Read from settings, admins should set this to true only when they chain to BungeeCord,
	it makes the server vulnerable to identity theft through direct connections. */
	bool ShouldAllowBungeeCord(void) const { return m_ShouldAllowBungeeCord; }
	
private:

	friend class cRoot;  // so cRoot can create and destroy cServer
	
	/** When NotifyClientWrite() is called, it is queued for this thread to process (to avoid deadlocks between cSocketThreads, cClientHandle and cChunkMap) */
	class cNotifyWriteThread :
		public cIsThread
	{
		typedef cIsThread super;
		
		cEvent    m_Event;  // Set when m_Clients gets appended
		cServer * m_Server;

		cCriticalSection  m_CS;
		cClientHandleList m_Clients;
		
		virtual void Execute(void);
		
	public:
	
		cNotifyWriteThread(void);
		~cNotifyWriteThread();
	
		bool Start(cServer * a_Server);
		
		void NotifyClientWrite(const cClientHandle * a_Client);
	} ;
	
	/** The server tick thread takes care of the players who aren't yet spawned in a world */
	class cTickThread :
		public cIsThread
	{
		typedef cIsThread super;
		
	public:
		cTickThread(cServer & a_Server);
		
	protected:
		cServer & m_Server;
		
		// cIsThread overrides:
		virtual void Execute(void) override;
	} ;
	
	
	cNotifyWriteThread m_NotifyWriteThread;
	
	cListenThread m_ListenThreadIPv4;
	cListenThread m_ListenThreadIPv6;
	
	cCriticalSection  m_CSClients;        ///< Locks client lists
	cClientHandleList m_Clients;          ///< Clients that are connected to the server and not yet assigned to a cWorld
	cClientHandleList m_ClientsToRemove;  ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick()
	
	mutable cCriticalSection m_CSPlayerCount;      ///< Locks the m_PlayerCount
	int              m_PlayerCount;        ///< Number of players currently playing in the server
	cCriticalSection m_CSPlayerCountDiff;  ///< Locks the m_PlayerCountDiff
	int              m_PlayerCountDiff;    ///< Adjustment to m_PlayerCount to be applied in the Tick thread
	
	cSocketThreads m_SocketThreads;
	
	int m_ClientViewDistance;  // The default view distance for clients; settable in Settings.ini

	bool m_bIsConnected;  // true - connected false - not connected

	bool m_bRestarting;
	
	/** The private key used for the assymetric encryption start in the protocols */
	cRsaPrivateKey m_PrivateKey;
	
	/** Public key for m_PrivateKey, ASN1-DER-encoded */
	AString m_PublicKeyDER;
	
	cRCONServer m_RCONServer;
	
	AString m_Description;
	AString m_FaviconData;
	int m_MaxPlayers;
	bool m_bIsHardcore;
	
	/** True - allow same username to login more than once False - only once */
	bool m_bAllowMultiLogin;
	
	cTickThread m_TickThread;
	cEvent m_RestartEvent;
	
	/** The server ID used for client authentication */
	AString m_ServerID;
	
	/** If true, players will be online-authenticated agains Mojang servers.
	This setting is the same as the "online-mode" setting in Vanilla. */
	bool m_ShouldAuthenticate;
	
	/** True if offline UUIDs should be used to load data for players whose normal UUIDs cannot be found.
	This allows transitions from an offline (no-auth) server to an online one.
	Loaded from the settings.ini [PlayerData].LoadOfflinePlayerData setting. */
	bool m_ShouldLoadOfflinePlayerData;
	
	/** True if old-style playernames should be used to load data for players whose regular datafiles cannot be found.
	This allows a seamless transition from name-based to UUID-based player storage.
	Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
	bool m_ShouldLoadNamedPlayerData;
	
	/** True if BungeeCord handshake packets (with player UUID) should be accepted. */
	bool m_ShouldAllowBungeeCord;


	cServer(void);

	/** Loads, or generates, if missing, RSA keys for protocol encryption */
	void PrepareKeys(void);
	
	bool Tick(float a_Dt);
	
	/** Ticks the clients in m_Clients, manages the list in respect to removing clients */
	void TickClients(float a_Dt);

	// cListenThread::cCallback overrides:
	virtual void OnConnectionAccepted(cSocket & a_Socket) override;
};  // tolua_export