Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 : #ifndef _CLIENTIFACE_H_
20 : #define _CLIENTIFACE_H_
21 :
22 : #include "irr_v3d.h" // for irrlicht datatypes
23 :
24 : #include "constants.h"
25 : #include "serialization.h" // for SER_FMT_VER_INVALID
26 : #include "jthread/jmutex.h"
27 : #include "network/networkpacket.h"
28 :
29 : #include <list>
30 : #include <vector>
31 : #include <map>
32 : #include <set>
33 :
34 : class MapBlock;
35 : class ServerEnvironment;
36 : class EmergeManager;
37 :
38 : /*
39 : * State Transitions
40 :
41 : Start
42 : (peer connect)
43 : |
44 : v
45 : /-----------------\
46 : | |
47 : | Created |
48 : | |
49 : \-----------------/
50 : | depending of the incoming packet
51 : +---------------------------------------
52 : v v
53 : +-----------------------------+ +-----------------------------+
54 : |IN: | |IN: |
55 : | TOSERVER_INIT_LEGACY |----- | TOSERVER_INIT | invalid playername,
56 : +-----------------------------+ | +-----------------------------+ password (for _LEGACY),
57 : | | | or denied by mod
58 : | Auth ok -------------------+---------------------------------
59 : v v |
60 : +-----------------------------+ +-----------------------------+ |
61 : |OUT: | |OUT: | |
62 : | TOCLIENT_INIT_LEGACY | | TOCLIENT_HELLO | |
63 : +-----------------------------+ +-----------------------------+ |
64 : | | |
65 : | | |
66 : v v |
67 : /-----------------\ /-----------------\ |
68 : | | | | |
69 : | AwaitingInit2 |<--------- | HelloSent | |
70 : | | | | | |
71 : \-----------------/ | \-----------------/ |
72 : | | | |
73 : +-----------------------------+ | *-----------------------------* Auth fails |
74 : |IN: | | |Authentication, depending on |-----------------+
75 : | TOSERVER_INIT2 | | | packet sent by client | |
76 : +-----------------------------+ | *-----------------------------* |
77 : | | | |
78 : | | | Authentication |
79 : v | | successful |
80 : /-----------------\ | v |
81 : | | | +-----------------------------+ |
82 : | InitDone | | |OUT: | |
83 : | | | | TOCLIENT_AUTH_ACCEPT | |
84 : \-----------------/ | +-----------------------------+ |
85 : | | | |
86 : +-----------------------------+ --------------------- |
87 : |OUT: | |
88 : | TOCLIENT_MOVEMENT | |
89 : | TOCLIENT_ITEMDEF | |
90 : | TOCLIENT_NODEDEF | |
91 : | TOCLIENT_ANNOUNCE_MEDIA | |
92 : | TOCLIENT_DETACHED_INVENTORY | |
93 : | TOCLIENT_TIME_OF_DAY | |
94 : +-----------------------------+ |
95 : | |
96 : | |
97 : | ----------------------------- |
98 : v | | |
99 : /-----------------\ v |
100 : | | +-----------------------------+ |
101 : | DefinitionsSent | |IN: | |
102 : | | | TOSERVER_REQUEST_MEDIA | |
103 : \-----------------/ | TOSERVER_RECEIVED_MEDIA | |
104 : | +-----------------------------+ |
105 : | ^ | |
106 : | ----------------------------- |
107 : v |
108 : +-----------------------------+ --------------------------------+
109 : |IN: | | |
110 : | TOSERVER_CLIENT_READY | v |
111 : +-----------------------------+ +-------------------------------+ |
112 : | |OUT: | |
113 : v | TOCLIENT_ACCESS_DENIED_LEGAGY | |
114 : +-----------------------------+ +-------------------------------+ |
115 : |OUT: | | |
116 : | TOCLIENT_MOVE_PLAYER | v |
117 : | TOCLIENT_PRIVILEGES | /-----------------\ |
118 : | TOCLIENT_INVENTORY_FORMSPEC | | | |
119 : | UpdateCrafting | | Denied | |
120 : | TOCLIENT_INVENTORY | | | |
121 : | TOCLIENT_HP (opt) | \-----------------/ |
122 : | TOCLIENT_BREATH | |
123 : | TOCLIENT_DEATHSCREEN | |
124 : +-----------------------------+ |
125 : | |
126 : v |
127 : /-----------------\ async mod action (ban, kick) |
128 : | |---------------------------------------------------------------
129 : ---->| Active |
130 : | | |----------------------------------------------
131 : | \-----------------/ timeout v
132 : | | | +-----------------------------+
133 : | | | |OUT: |
134 : | | | | TOCLIENT_DISCONNECT |
135 : | | | +-----------------------------+
136 : | | | |
137 : | | v v
138 : | | +-----------------------------+ /-----------------\
139 : | | |IN: | | |
140 : | | | TOSERVER_DISCONNECT |------------------->| Disconnecting |
141 : | | +-----------------------------+ | |
142 : | | \-----------------/
143 : | | any auth packet which was
144 : | | allowed in TOCLIENT_AUTH_ACCEPT
145 : | v
146 : | *-----------------------------* Auth +-------------------------------+
147 : | |Authentication, depending on | succeeds |OUT: |
148 : | | packet sent by client |---------->| TOCLIENT_ACCEPT_SUDO_MODE |
149 : | *-----------------------------* +-------------------------------+
150 : | | |
151 : | | Auth fails /-----------------\
152 : | v | |
153 : | +-------------------------------+ | SudoMode |
154 : | |OUT: | | |
155 : | | TOCLIENT_DENY_SUDO_MODE | \-----------------/
156 : | +-------------------------------+ |
157 : | | v
158 : | | +-----------------------------+
159 : | | sets password accordingly |IN: |
160 : -------------------+-------------------------------| TOSERVER_FIRST_SRP |
161 : +-----------------------------+
162 :
163 : */
164 : namespace con {
165 : class Connection;
166 : }
167 :
168 : #define CI_ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
169 :
170 : enum ClientState
171 : {
172 : CS_Invalid,
173 : CS_Disconnecting,
174 : CS_Denied,
175 : CS_Created,
176 : CS_AwaitingInit2,
177 : CS_HelloSent,
178 : CS_InitDone,
179 : CS_DefinitionsSent,
180 : CS_Active,
181 : CS_SudoMode
182 : };
183 :
184 : enum ClientStateEvent
185 : {
186 : CSE_Hello,
187 : CSE_AuthAccept,
188 : CSE_InitLegacy,
189 : CSE_GotInit2,
190 : CSE_SetDenied,
191 : CSE_SetDefinitionsSent,
192 : CSE_SetClientReady,
193 : CSE_SudoSuccess,
194 : CSE_SudoLeave,
195 : CSE_Disconnect
196 : };
197 :
198 : /*
199 : Used for queueing and sorting block transfers in containers
200 :
201 : Lower priority number means higher priority.
202 : */
203 0 : struct PrioritySortedBlockTransfer
204 : {
205 0 : PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
206 0 : {
207 0 : priority = a_priority;
208 0 : pos = a_pos;
209 0 : peer_id = a_peer_id;
210 0 : }
211 0 : bool operator < (const PrioritySortedBlockTransfer &other) const
212 : {
213 0 : return priority < other.priority;
214 : }
215 : float priority;
216 : v3s16 pos;
217 : u16 peer_id;
218 : };
219 :
220 : class RemoteClient
221 : {
222 : public:
223 : // peer_id=0 means this client has no associated peer
224 : // NOTE: If client is made allowed to exist while peer doesn't,
225 : // this has to be set to 0 when there is no peer.
226 : // Also, the client must be moved to some other container.
227 : u16 peer_id;
228 : // The serialization version to use with the client
229 : u8 serialization_version;
230 : //
231 : u16 net_proto_version;
232 :
233 : /* Authentication information */
234 : std::string enc_pwd;
235 : AuthMechanism chosen_mech;
236 : void * auth_data;
237 : u32 allowed_auth_mechs;
238 : u32 allowed_sudo_mechs;
239 :
240 0 : bool isSudoMechAllowed(AuthMechanism mech)
241 0 : { return allowed_sudo_mechs & mech; }
242 0 : bool isMechAllowed(AuthMechanism mech)
243 0 : { return allowed_auth_mechs & mech; }
244 :
245 0 : RemoteClient():
246 : peer_id(PEER_ID_INEXISTENT),
247 : serialization_version(SER_FMT_VER_INVALID),
248 : net_proto_version(0),
249 : chosen_mech(AUTH_MECHANISM_NONE),
250 : auth_data(NULL),
251 : m_time_from_building(9999),
252 : m_pending_serialization_version(SER_FMT_VER_INVALID),
253 : m_state(CS_Created),
254 : m_nearest_unsent_d(0),
255 : m_nearest_unsent_reset_timer(0.0),
256 : m_excess_gotblocks(0),
257 : m_nothing_to_send_pause_timer(0.0),
258 : m_name(""),
259 : m_version_major(0),
260 : m_version_minor(0),
261 : m_version_patch(0),
262 : m_full_version("unknown"),
263 : m_deployed_compression(0),
264 0 : m_connection_time(getTime(PRECISION_SECONDS))
265 : {
266 0 : }
267 0 : ~RemoteClient()
268 0 : {
269 0 : }
270 :
271 : /*
272 : Finds block that should be sent next to the client.
273 : Environment should be locked when this is called.
274 : dtime is used for resetting send radius at slow interval
275 : */
276 : void GetNextBlocks(ServerEnvironment *env, EmergeManager* emerge,
277 : float dtime, std::vector<PrioritySortedBlockTransfer> &dest);
278 :
279 : void GotBlock(v3s16 p);
280 :
281 : void SentBlock(v3s16 p);
282 :
283 : void SetBlockNotSent(v3s16 p);
284 : void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
285 :
286 : /**
287 : * tell client about this block being modified right now.
288 : * this information is required to requeue the block in case it's "on wire"
289 : * while modification is processed by server
290 : * @param p position of modified block
291 : */
292 : void ResendBlockIfOnWire(v3s16 p);
293 :
294 0 : s32 SendingCount()
295 : {
296 0 : return m_blocks_sending.size();
297 : }
298 :
299 : // Increments timeouts and removes timed-out blocks from list
300 : // NOTE: This doesn't fix the server-not-sending-block bug
301 : // because it is related to emerging, not sending.
302 : //void RunSendingTimeouts(float dtime, float timeout);
303 :
304 0 : void PrintInfo(std::ostream &o)
305 : {
306 0 : o<<"RemoteClient "<<peer_id<<": "
307 0 : <<"m_blocks_sent.size()="<<m_blocks_sent.size()
308 0 : <<", m_blocks_sending.size()="<<m_blocks_sending.size()
309 0 : <<", m_nearest_unsent_d="<<m_nearest_unsent_d
310 0 : <<", m_excess_gotblocks="<<m_excess_gotblocks
311 0 : <<std::endl;
312 0 : m_excess_gotblocks = 0;
313 0 : }
314 :
315 : // Time from last placing or removing blocks
316 : float m_time_from_building;
317 :
318 : /*
319 : List of active objects that the client knows of.
320 : Value is dummy.
321 : */
322 : std::set<u16> m_known_objects;
323 :
324 0 : ClientState getState()
325 0 : { return m_state; }
326 :
327 0 : std::string getName()
328 0 : { return m_name; }
329 :
330 0 : void setName(std::string name)
331 0 : { m_name = name; }
332 :
333 : /* update internal client state */
334 : void notifyEvent(ClientStateEvent event);
335 :
336 : /* set expected serialization version */
337 0 : void setPendingSerializationVersion(u8 version)
338 0 : { m_pending_serialization_version = version; }
339 :
340 0 : void setDeployedCompressionMode(u16 byteFlag)
341 0 : { m_deployed_compression = byteFlag; }
342 :
343 0 : void confirmSerializationVersion()
344 0 : { serialization_version = m_pending_serialization_version; }
345 :
346 : /* get uptime */
347 : u32 uptime();
348 :
349 : /* set version information */
350 0 : void setVersionInfo(u8 major, u8 minor, u8 patch, std::string full) {
351 0 : m_version_major = major;
352 0 : m_version_minor = minor;
353 0 : m_version_patch = patch;
354 0 : m_full_version = full;
355 0 : }
356 :
357 : /* read version information */
358 0 : u8 getMajor() { return m_version_major; }
359 0 : u8 getMinor() { return m_version_minor; }
360 0 : u8 getPatch() { return m_version_patch; }
361 : std::string getVersion() { return m_full_version; }
362 : private:
363 : // Version is stored in here after INIT before INIT2
364 : u8 m_pending_serialization_version;
365 :
366 : /* current state of client */
367 : ClientState m_state;
368 :
369 : /*
370 : Blocks that have been sent to client.
371 : - These don't have to be sent again.
372 : - A block is cleared from here when client says it has
373 : deleted it from it's memory
374 :
375 : Key is position, value is dummy.
376 : No MapBlock* is stored here because the blocks can get deleted.
377 : */
378 : std::set<v3s16> m_blocks_sent;
379 : s16 m_nearest_unsent_d;
380 : v3s16 m_last_center;
381 : float m_nearest_unsent_reset_timer;
382 :
383 : /*
384 : Blocks that are currently on the line.
385 : This is used for throttling the sending of blocks.
386 : - The size of this list is limited to some value
387 : Block is added when it is sent with BLOCKDATA.
388 : Block is removed when GOTBLOCKS is received.
389 : Value is time from sending. (not used at the moment)
390 : */
391 : std::map<v3s16, float> m_blocks_sending;
392 :
393 : /*
394 : Count of excess GotBlocks().
395 : There is an excess amount because the client sometimes
396 : gets a block so late that the server sends it again,
397 : and the client then sends two GOTBLOCKs.
398 : This is resetted by PrintInfo()
399 : */
400 : u32 m_excess_gotblocks;
401 :
402 : // CPU usage optimization
403 : float m_nothing_to_send_pause_timer;
404 :
405 : /*
406 : name of player using this client
407 : */
408 : std::string m_name;
409 :
410 : /*
411 : client information
412 : */
413 : u8 m_version_major;
414 : u8 m_version_minor;
415 : u8 m_version_patch;
416 :
417 : std::string m_full_version;
418 :
419 : u16 m_deployed_compression;
420 :
421 : /*
422 : time this client was created
423 : */
424 : const u32 m_connection_time;
425 : };
426 :
427 : class ClientInterface {
428 : public:
429 :
430 : friend class Server;
431 :
432 : ClientInterface(con::Connection* con);
433 : ~ClientInterface();
434 :
435 : /* run sync step */
436 : void step(float dtime);
437 :
438 : /* get list of active client id's */
439 : std::vector<u16> getClientIDs(ClientState min_state=CS_Active);
440 :
441 : /* get list of client player names */
442 : std::vector<std::string> getPlayerNames();
443 :
444 : /* send message to client */
445 : void send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable);
446 :
447 : /* send to all clients */
448 : void sendToAll(u16 channelnum, NetworkPacket* pkt, bool reliable);
449 :
450 : /* delete a client */
451 : void DeleteClient(u16 peer_id);
452 :
453 : /* create client */
454 : void CreateClient(u16 peer_id);
455 :
456 : /* get a client by peer_id */
457 : RemoteClient* getClientNoEx(u16 peer_id, ClientState state_min=CS_Active);
458 :
459 : /* get client by peer_id (make sure you have list lock before!*/
460 : RemoteClient* lockedGetClientNoEx(u16 peer_id, ClientState state_min=CS_Active);
461 :
462 : /* get state of client by id*/
463 : ClientState getClientState(u16 peer_id);
464 :
465 : /* set client playername */
466 : void setPlayerName(u16 peer_id,std::string name);
467 :
468 : /* get protocol version of client */
469 : u16 getProtocolVersion(u16 peer_id);
470 :
471 : /* set client version */
472 : void setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full);
473 :
474 : /* event to update client state */
475 : void event(u16 peer_id, ClientStateEvent event);
476 :
477 : /* Set environment. Do not call this function if environment is already set */
478 0 : void setEnv(ServerEnvironment *env)
479 : {
480 : assert(m_env == NULL); // pre-condition
481 0 : m_env = env;
482 0 : }
483 :
484 : static std::string state2Name(ClientState state);
485 :
486 : protected:
487 : //TODO find way to avoid this functions
488 0 : void Lock()
489 0 : { m_clients_mutex.Lock(); }
490 0 : void Unlock()
491 0 : { m_clients_mutex.Unlock(); }
492 :
493 0 : std::map<u16, RemoteClient*>& getClientList()
494 0 : { return m_clients; }
495 :
496 : private:
497 : /* update internal player list */
498 : void UpdatePlayerList();
499 :
500 : // Connection
501 : con::Connection* m_con;
502 : JMutex m_clients_mutex;
503 : // Connected clients (behind the con mutex)
504 : std::map<u16, RemoteClient*> m_clients;
505 : std::vector<std::string> m_clients_names; //for announcing masterserver
506 :
507 : // Environment
508 : ServerEnvironment *m_env;
509 : JMutex m_env_mutex;
510 :
511 : float m_print_info_timer;
512 :
513 : static const char *statenames[];
514 : };
515 :
516 : #endif
|