]> git.lizzy.rs Git - minetest.git/blob - src/clientiface.h
src/network/connection.h: Fix race condition
[minetest.git] / src / clientiface.h
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 struct PrioritySortedBlockTransfer
204 {
205         PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
206         {
207                 priority = a_priority;
208                 pos = a_pos;
209                 peer_id = a_peer_id;
210         }
211         bool operator < (const PrioritySortedBlockTransfer &other) const
212         {
213                 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         bool create_player_on_auth_success;
236         AuthMechanism chosen_mech;
237         void * auth_data;
238         u32 allowed_auth_mechs;
239         u32 allowed_sudo_mechs;
240
241         bool isSudoMechAllowed(AuthMechanism mech)
242         { return allowed_sudo_mechs & mech; }
243         bool isMechAllowed(AuthMechanism mech)
244         { return allowed_auth_mechs & mech; }
245
246         RemoteClient():
247                 peer_id(PEER_ID_INEXISTENT),
248                 serialization_version(SER_FMT_VER_INVALID),
249                 net_proto_version(0),
250                 create_player_on_auth_success(false),
251                 chosen_mech(AUTH_MECHANISM_NONE),
252                 auth_data(NULL),
253                 m_time_from_building(9999),
254                 m_pending_serialization_version(SER_FMT_VER_INVALID),
255                 m_state(CS_Created),
256                 m_nearest_unsent_d(0),
257                 m_nearest_unsent_reset_timer(0.0),
258                 m_excess_gotblocks(0),
259                 m_nothing_to_send_pause_timer(0.0),
260                 m_name(""),
261                 m_version_major(0),
262                 m_version_minor(0),
263                 m_version_patch(0),
264                 m_full_version("unknown"),
265                 m_deployed_compression(0),
266                 m_connection_time(getTime(PRECISION_SECONDS))
267         {
268         }
269         ~RemoteClient()
270         {
271         }
272
273         /*
274                 Finds block that should be sent next to the client.
275                 Environment should be locked when this is called.
276                 dtime is used for resetting send radius at slow interval
277         */
278         void GetNextBlocks(ServerEnvironment *env, EmergeManager* emerge,
279                         float dtime, std::vector<PrioritySortedBlockTransfer> &dest);
280
281         void GotBlock(v3s16 p);
282
283         void SentBlock(v3s16 p);
284
285         void SetBlockNotSent(v3s16 p);
286         void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
287
288         /**
289          * tell client about this block being modified right now.
290          * this information is required to requeue the block in case it's "on wire"
291          * while modification is processed by server
292          * @param p position of modified block
293          */
294         void ResendBlockIfOnWire(v3s16 p);
295
296         s32 SendingCount()
297         {
298                 return m_blocks_sending.size();
299         }
300
301         // Increments timeouts and removes timed-out blocks from list
302         // NOTE: This doesn't fix the server-not-sending-block bug
303         //       because it is related to emerging, not sending.
304         //void RunSendingTimeouts(float dtime, float timeout);
305
306         void PrintInfo(std::ostream &o)
307         {
308                 o<<"RemoteClient "<<peer_id<<": "
309                                 <<"m_blocks_sent.size()="<<m_blocks_sent.size()
310                                 <<", m_blocks_sending.size()="<<m_blocks_sending.size()
311                                 <<", m_nearest_unsent_d="<<m_nearest_unsent_d
312                                 <<", m_excess_gotblocks="<<m_excess_gotblocks
313                                 <<std::endl;
314                 m_excess_gotblocks = 0;
315         }
316
317         // Time from last placing or removing blocks
318         float m_time_from_building;
319
320         /*
321                 List of active objects that the client knows of.
322                 Value is dummy.
323         */
324         std::set<u16> m_known_objects;
325
326         ClientState getState()
327                 { return m_state; }
328
329         std::string getName()
330                 { return m_name; }
331
332         void setName(std::string name)
333                 { m_name = name; }
334
335         /* update internal client state */
336         void notifyEvent(ClientStateEvent event);
337
338         /* set expected serialization version */
339         void setPendingSerializationVersion(u8 version)
340                 { m_pending_serialization_version = version; }
341
342         void setDeployedCompressionMode(u16 byteFlag)
343                 { m_deployed_compression = byteFlag; }
344
345         void confirmSerializationVersion()
346                 { serialization_version = m_pending_serialization_version; }
347
348         /* get uptime */
349         u32 uptime();
350
351         /* set version information */
352         void setVersionInfo(u8 major, u8 minor, u8 patch, std::string full) {
353                 m_version_major = major;
354                 m_version_minor = minor;
355                 m_version_patch = patch;
356                 m_full_version = full;
357         }
358
359         /* read version information */
360         u8 getMajor() { return m_version_major; }
361         u8 getMinor() { return m_version_minor; }
362         u8 getPatch() { return m_version_patch; }
363         std::string getVersion() { return m_full_version; }
364 private:
365         // Version is stored in here after INIT before INIT2
366         u8 m_pending_serialization_version;
367
368         /* current state of client */
369         ClientState m_state;
370
371         /*
372                 Blocks that have been sent to client.
373                 - These don't have to be sent again.
374                 - A block is cleared from here when client says it has
375                   deleted it from it's memory
376
377                 Key is position, value is dummy.
378                 No MapBlock* is stored here because the blocks can get deleted.
379         */
380         std::set<v3s16> m_blocks_sent;
381         s16 m_nearest_unsent_d;
382         v3s16 m_last_center;
383         float m_nearest_unsent_reset_timer;
384
385         /*
386                 Blocks that are currently on the line.
387                 This is used for throttling the sending of blocks.
388                 - The size of this list is limited to some value
389                 Block is added when it is sent with BLOCKDATA.
390                 Block is removed when GOTBLOCKS is received.
391                 Value is time from sending. (not used at the moment)
392         */
393         std::map<v3s16, float> m_blocks_sending;
394
395         /*
396                 Count of excess GotBlocks().
397                 There is an excess amount because the client sometimes
398                 gets a block so late that the server sends it again,
399                 and the client then sends two GOTBLOCKs.
400                 This is resetted by PrintInfo()
401         */
402         u32 m_excess_gotblocks;
403
404         // CPU usage optimization
405         float m_nothing_to_send_pause_timer;
406
407         /*
408                 name of player using this client
409         */
410         std::string m_name;
411
412         /*
413                 client information
414          */
415         u8 m_version_major;
416         u8 m_version_minor;
417         u8 m_version_patch;
418
419         std::string m_full_version;
420
421         u16 m_deployed_compression;
422
423         /*
424                 time this client was created
425          */
426         const u32 m_connection_time;
427 };
428
429 class ClientInterface {
430 public:
431
432         friend class Server;
433
434         ClientInterface(con::Connection* con);
435         ~ClientInterface();
436
437         /* run sync step */
438         void step(float dtime);
439
440         /* get list of active client id's */
441         std::vector<u16> getClientIDs(ClientState min_state=CS_Active);
442
443         /* get list of client player names */
444         std::vector<std::string> getPlayerNames();
445
446         /* send message to client */
447         void send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable);
448
449         /* send to all clients */
450         void sendToAll(u16 channelnum, NetworkPacket* pkt, bool reliable);
451
452         /* delete a client */
453         void DeleteClient(u16 peer_id);
454
455         /* create client */
456         void CreateClient(u16 peer_id);
457
458         /* get a client by peer_id */
459         RemoteClient* getClientNoEx(u16 peer_id,  ClientState state_min=CS_Active);
460
461         /* get client by peer_id (make sure you have list lock before!*/
462         RemoteClient* lockedGetClientNoEx(u16 peer_id,  ClientState state_min=CS_Active);
463
464         /* get state of client by id*/
465         ClientState getClientState(u16 peer_id);
466
467         /* set client playername */
468         void setPlayerName(u16 peer_id,std::string name);
469
470         /* get protocol version of client */
471         u16 getProtocolVersion(u16 peer_id);
472
473         /* set client version */
474         void setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full);
475
476         /* event to update client state */
477         void event(u16 peer_id, ClientStateEvent event);
478
479         /* Set environment. Do not call this function if environment is already set */
480         void setEnv(ServerEnvironment *env)
481         {
482                 assert(m_env == NULL); // pre-condition
483                 m_env = env;
484         }
485
486         static std::string state2Name(ClientState state);
487
488 protected:
489         //TODO find way to avoid this functions
490         void Lock()
491                 { m_clients_mutex.Lock(); }
492         void Unlock()
493                 { m_clients_mutex.Unlock(); }
494
495         std::map<u16, RemoteClient*>& getClientList()
496                 { return m_clients; }
497
498 private:
499         /* update internal player list */
500         void UpdatePlayerList();
501
502         // Connection
503         con::Connection* m_con;
504         JMutex m_clients_mutex;
505         // Connected clients (behind the con mutex)
506         std::map<u16, RemoteClient*> m_clients;
507         std::vector<std::string> m_clients_names; //for announcing masterserver
508
509         // Environment
510         ServerEnvironment *m_env;
511         JMutex m_env_mutex;
512
513         float m_print_info_timer;
514
515         static const char *statenames[];
516 };
517
518 #endif