1 /*
2  * Copyright (C) 2012-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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 this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_NETWORK_INTERNET_GAMING_PROTOCOL_H
21 #define WL_NETWORK_INTERNET_GAMING_PROTOCOL_H
22 
23 #include <string>
24 
25 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26  * BASIC SETUP VALUES                                                      *
27  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
28 
29 /**
30  * The current version of the in-game network protocol. Client and metaserver
31  * protocol versions must match. The metaserver supports the protocol version of latest stable build
32  * and the newest version in trunk.
33  * Used Versions:
34  * 0: Build 19 and before [stable, supported]
35  * 1: Between build 19 and build 20 - IPv6 support added
36  * 2: Between build 19 and build 20 - Added UUID to allow reconnect with same username after
37  *    crashes. When logging twice with a registered account, the second connection gets a free
38  *     username assigned. Dropping RELOGIN command.
39  * 3: Between build 19 and build 20 - Added network relay for internet games
40  * 4: Between build 19 and build 20 - Using CHAP for password authentication
41  * 5: Build 20 - Removed obsolete TELL_IP, modifications on user and game listing [supported]
42  * 6: Between build 20 and build 21 - Added CHECK_PWD and PWD_OK commands
43  */
44 constexpr unsigned int kInternetGamingProtocolVersion = 6;
45 
46 /**
47  * The default timeout time after which the client tries to resend a package or even finally closes
48  * the
49  * connection to the metaserver, if no answer to a previous package (which requires an answer) was
50  * received. In case of a login or reconnect, this is the time to wait for the metaservers answer.
51  *
52  * value is in milliseconds
53  */
54 // TODO(unknown): Should this be resettable by the user?
55 constexpr time_t kInternetGamingTimeout = 10;  // 10 seconds
56 
57 /// Metaserver connection details
58 static const std::string INTERNET_GAMING_METASERVER = "widelands.org";
59 // Default port for connecting to the metaserver
60 constexpr uint16_t kInternetGamingPort = 7395;
61 // Default port for connecting to the relay
62 constexpr uint16_t kInternetRelayPort = 7397;
63 // The following ones are only used between metaserver and relay
64 // Port used by the metaserver to contact the relay
65 // INTERNET_RELAY_RPC_PORT 7398
66 // Port used by the relay to contact the metaserver
67 // INTERNET_GAMING_RPC_PORT 7399
68 
69 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
70  * CLIENT RIGHTS                                                           *
71  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
72 /// Client rights
73 static const std::string INTERNET_CLIENT_UNREGISTERED = "UNREGISTERED";
74 static const std::string INTERNET_CLIENT_REGISTERED = "REGISTERED";
75 static const std::string INTERNET_CLIENT_SUPERUSER = "SUPERUSER";
76 static const std::string INTERNET_CLIENT_IRC = "IRC";
77 
78 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
79  * GAME STATUS                                                             *
80  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
81 /// States an online game can be in.
82 /// Other values might appear but should be considered as "CLOSED"
83 static const std::string INTERNET_GAME_CLOSED = "CLOSED";  // Not yet connectable or not over relay
84 static const std::string INTERNET_GAME_SETUP = "SETUP";    // Map selection and so
85 static const std::string INTERNET_GAME_RUNNING = "RUNNING";  // Playing
86 
87 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
88  * COMMUNICATION PROTOCOL BETWEEN CLIENT AND METASERVER                    *
89  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 /**
91  * Below are the command codes used in the internet gaming protocol.
92  *
93  * The internet gaming protocol is responsible for the communication between the
94  * metaserver and the clients.
95  *
96  * The network stream of the internet gaming protocol is split up into
97  * packets (see \ref RecvPacket, \ref SendPacket).
98  * Every packet starts with a single-byte command code.
99  *
100  * \note ALL PAYLOADS SHALL BE STRINGS - this is for easier handling and debugging of the
101  *       communication between metaserver and client. If an unsigned or signed value has
102  *       to be sent, convert it with boost::lexical_cast<std::string>. Boolean values should
103          be sent in form of "true" or "false".
104  */
105 
106 /**
107  * The UUID:
108  *
109  * The UUID is a semi-permanent ID stored in the configuration file of Widelands.
110  * It has to be stored in the file since it should survive crashes of the game or computer.
111  * If the game is not started for 24 hours, a new one is created to increase privacy.
112  * Basically it allows the metaserver to identify the user even when multiple users try to join with
113  * the same username. Note that the sent UUID differs from the stored one: The sent UUID is
114  * hash(username | stored-id).
115  * In the case of registered players, the password can be used instead of a UUID. The username
116  * alone can not be used for this, especially not for unregistered users: The metaserver can not
117  * differentiate between a second connection by the user and an initial login of another user
118  * (with the same name).
119  *
120  * Use-cases of the UUID:
121  *
122  * Reconnect after crash / network problems.
123  * When Widelands breaks the connection without logging out, the server still assumes that the old
124  * connection is active. So when the player reconnects, another name is chosen. Sending the UUID
125  * allows to reclaim the old name, since the server recognizes that there isn't a second player
126  * trying to use the same name.
127  */
128 
129 /**
130  * Bidirectional command: Terminate the connection with a given reason.
131  *
132  * Payload is:
133  * \li string: reason for disconnect in message code (see internet_gaming_messages.h)
134  *
135  * Both metaserver and client can send this command, followed by immediately
136  * closing the connection. The receiver of this command should just close the connection.
137  *
138  * \note that either party is allowed to close the connection without sending a \ref
139  *       IGPCMD_DISCONNECT command first (in any case, this can happen when the program crashes
140  *       or network connection is lost).
141  *
142  * \note If you want to change the payload of this command, change it only by appending new items.
143  *       The reason is that this is the only command that can be sent by the metaserver even when
144  *       the protocol versions differ.
145  *
146  */
147 static const std::string IGPCMD_DISCONNECT = "DISCONNECT";
148 
149 /**
150  * Initiate a connection.
151  *
152  * The first communication across the network stream is a IGPCMD_LOGIN command
153  * sent by the client, with the following payload:
154  * \li string:    protocol version (see kInternetGamingProtocolVersion)
155  * \li string:    client name
156  * \li string:    build_id of the client
157  * \li string:    whether the client wants to login in to a registered account
158  *                ("true" or "false" as string)
159  * \li string:    for registered accounts: string of length 0
160  *                for unregistered users the UUID to recognize the matching IPv4 and IPv6
161  *                connections or to reclaim the username after a unintended disconnect.
162  *                For an explanation of the UUID, see above.
163  *
164  * If the user tries to login to a registered account, a IGPCMD_PWD_CHALLENGE exchange follows
165  * before
166  * the server replies with a IGPCMD_LOGIN or IGPCMD_ERROR message.
167  *
168  * If the metaserver accepts, it replies with a IGPCMD_LOGIN command with the following payload:
169  * \li string:    client name. Might be different to the previously chosen one, if the chosen
170  *                name already used or is registered (and the connecting client is not registered).
171  * \li string:    clients rights (see client rights section above)
172  *
173  * When the client is downgraded to an unregistered user on login, a special UUID value
174  * of sha1(assignedName | passwordHash) has to be used on reconnects.
175  *
176  * If no answer is received in \ref kInternetGamingTimeout seconds the client will again try to
177  * login
178  * \ref INTERNET_GAMING_RETRIES times until it finally bails out something like "server does not
179  * answer"
180  *
181  * For the case, that the metaserver does not accept the login, take a look at \ref IGPCMD_ERROR
182  */
183 static const std::string IGPCMD_LOGIN = "LOGIN";
184 
185 /**
186  * The client tries to check the password of the user without doing a full login.
187  * Should be sent without logging in before.
188  *
189  * Payload:
190  * \li string:    protocol version (see kInternetGamingProtocolVersion)
191  * \li string:    client name
192  * \li string:    build_id of the client
193  *
194  * A IGPCMD_PWD_CHALLENGE exchange follows before the server replies with a IGPCMD_PWD_OK
195  * or IGPCMD_ERROR message.
196  *
197  * If the password is correct, the metaserver replies with a IGPCMD_PWD_OK command
198  * with the following payload:
199  * \li string:    client name. Will be the same as sent before.
200  * \li string:    clients rights (see client rights section above)
201  *
202  * If the password is wrong or some other error occurred, \ref IGPCMD_ERROR is returned.
203  */
204 static const std::string IGPCMD_CHECK_PWD = "CHECK_PWD";
205 static const std::string IGPCMD_PWD_OK = "PWD_OK";
206 
207 /**
208  * This is sent by the metaserver after a IGPCMD_LOGIN or IGPCMD_CHECK_PWD by a registered client.
209  * This is the first message of the a protocol similar to the challenge handshake authentication
210  * protocol (CHAP) for secure transmission of the users password.
211  * The server sends the nonce for hashing:
212  * \li string:    a nonce for hashing
213  *
214  * The client should answer the message by an own IGPCMD_PWD_CHALLENGE containing the hashed
215  * password:
216  * \li string:    HASH_SHA1(nonce | HASH_SHA1(password))
217  *
218  * If the transmitted value is correct, the normal IGPCMD_LOGIN sequence continues.
219  * If the
220  * value is wrong (e.g., wrong password) the connection is terminated by the servers
221  * IGPCMD_DISCONNECT.
222  */
223 static const std::string IGPCMD_PWD_CHALLENGE = "PWD_CHALLENGE";
224 
225 /**
226  * This command is sent by the metaserver if something went wrong.
227  * At least the following payload:
228  * \li string:    IGPCMD code of the message that lead to the ERROR message or ERROR
229  * GARBAGE_RECEIVED if
230  *                the received code was unknown.
231  * \li string:    explanation code or the string that was sent, if ERROR GARBAGE_RECEIVED
232  *
233  * \note all this is handled in InternetGaming::handle_packet. valid explanation codes can be found
234  * there.
235  * \note example for not connectable game: "ERROR" "GAME_OPEN"
236  */
237 static const std::string IGPCMD_ERROR = "ERROR";
238 
239 /**
240  * This is sent by the metaserver to inform the client, about the metaserver time = time(0). Payload
241  * \li string:    the server time
242  */
243 static const std::string IGPCMD_TIME = "TIME";
244 
245 /**
246  * This is sent by a superuser client to change the motd. The server has to check the permissions
247  * and if those
248  * allow a motd change has to change the motd and afterwards to broadcast the new motd to all
249  * clients.
250  * If the client has no right to change the motd, the server disconnects the client with a
251  * permission denied
252  * message. It should further log that try to access superuser functionality.
253  * \li string:    new motd
254  */
255 static const std::string IGPCMD_MOTD = "MOTD";
256 
257 /**
258  * This is sent by a superuser client as announcement. The server has to check the permissions and
259  * if those
260  * allow an announcement, the server broadcasts the announcement as system chat to all clients.
261  * If the client has no right to change the motd, the server disconnects the client with a
262  * permission denied
263  * message. It should further log that try to access superuser functionality.
264  * \li string:    announcement message
265  */
266 static const std::string IGPCMD_ANNOUNCEMENT = "ANNOUNCEMENT";
267 
268 // in future here should the other superuser commands be
269 
270 /**
271  * Sent by the metaserver without payload. The client must reply with a \ref IGPCMD_PONG command.
272  * If the client does not answer on a PING within \ref INTERNET_GAMING_CLIENT_TIMEOUT s it gets
273  * disconnected.
274  */
275 static const std::string IGPCMD_PING = "PING";
276 
277 /**
278  * Reply to a \ref IGPCMD_PING command, without payload.
279  */
280 static const std::string IGPCMD_PONG = "PONG";
281 
282 /**
283  * Sent by both metaserver and client to exchange chat messages, though with different payloads.
284  *
285  * The client sends this message to the metaserver with the following payload:
286  * \li string:    the message
287  * \li string:    name of client, if private message, else empty string.
288  * The metaserver will echo the message if the client is allowed to send chat messages.
289  *
290  * The metaserver either broadcasts a chat message to all clients or sends it to the pm recipient
291  * with the following payload:
292  * \li string:    sender (may be empty if it is a system message)
293  * \li string:    the message
294  * \li string:    type ("public", "private", "system")
295  *
296  * \note system messages are the motd (Sent by the metaserver to the client, after login
297  * (but not relogin) and after the motd got changed) and announcements by superusers.
298  */
299 static const std::string IGPCMD_CHAT = "CHAT";
300 
301 /**
302  * Sent by the client to issue a superuser command.
303  *
304  * The client sends this message to the metaserver with the following payload:
305  * \li string:    the command
306  * \li string:    arbitrary parameters.
307  */
308 static const std::string IGPCMD_CMD = "CMD";
309 
310 /**
311  * Sent by the metaserver to inform the client, that the list of games was changed. No payload is
312  * sent,
313  * as e.g. clients in a game are not really interested about other games and we want to keep traffic
314  * as low as possible.
315  *
316  * To get the new list of games, the client must send \ref IGPCMD_GAMES
317  */
318 static const std::string IGPCMD_GAMES_UPDATE = "GAMES_UPDATE";
319 
320 /**
321  * Sent by the client without payload to ask for the current list of games.
322  *
323  * Sent by the metaserver with following payload:
324  * \li string:    Number of game packages and for uint8_t i = 0; i < num; ++i {:
325  * \li string:    Name of the game
326  * \li string:    Widelands version
327  * \li string:    Status of the game, see above. Note that only because a game is connectable
328  *                this does not mean that gaming will work when the versions differ
329  * }
330  */
331 static const std::string IGPCMD_GAMES = "GAMES";
332 
333 /**
334  * Sent by the metaserver to inform the client, that the list of clients was changed. No payload is
335  * sent, as e.g. clients in a game are not really interested about other clients and we want to
336  * keep traffic as low as possible.
337  *
338  * To get the new list of clients, the client must send \ref IGPCMD_CLIENT
339  */
340 static const std::string IGPCMD_CLIENTS_UPDATE = "CLIENTS_UPDATE";
341 
342 /**
343  * Sent by the client without payload to ask for the current list of clients.
344  *
345  * Sent by the metaserver with following payload:
346  * \li string:    Number of client packages and for uint8_t i = 0; i < num; ++i {:
347  * \li string:    Name of the client
348  * \li string:    Widelands version
349  * \li string:    Game the player is connected to, else empty
350  * \li string:    Clients rights (see client rights section above)
351  * }
352  */
353 static const std::string IGPCMD_CLIENTS = "CLIENTS";
354 
355 /**
356  * Sent by the client to announce the startup of a game with following payload:
357  * \li string:    name of the game
358  * \note build_id is not necessary, as this is the build_id of the hosting client anyway.
359  *
360  * Sent by the metaserver to acknowledge the startup of a new game with the following payload:
361  * \li string:    a challenge that has to be "solved" to work as host of the new game.
362  *                See IGPCMD_PWD_CHALLENGE. The response is send to the relay
363  * \li string:    primary ip of relay server for the game.
364  * \li string:    whether a secondary ip for the relay follows ("true" or "false" as string)
365  * \li string:    secondary ip of the relay - only valid if previous was true
366  * The metaserver will list the new game, but set it as not connectable.
367  * When the client connects to the relay within kInternetGamingTimeout milliseconds,
368  * the metaserver lists the game as connectable, else it removes the game from the list of games.
369  */
370 static const std::string IGPCMD_GAME_OPEN = "GAME_OPEN";
371 
372 /**
373  * Sent by the client to initialize the connection to a game with following payload:
374  * \li string:    name of the game the client wants to connect to
375  * \note the client will wait for the metaserver answer, as it needs the ip adress. if the answer is
376  *       not received at time it will retry until the maximum numbers of retries is reached and the
377  *       client finally closes the connection.
378  *
379  * Sent by the metaserver to acknowledge the connection request and to submit the ip of the game
380  * \li string:    primary ip of the game.
381  * \li string:    whether a secondary ip for the game follows ("true" or "false" as string)
382  * \li string:    secondary ip of the game - only valid if previous was true
383  * \note as soon as this message is sent, the metaserver will list the client as connected to the
384  * game.
385  */
386 static const std::string IGPCMD_GAME_CONNECT = "GAME_CONNECT";
387 
388 /**
389  * Sent by the client to close the connection to a game without payload, as the client can
390  * only be on one game at time.
391  * This is the case in *every* way a client leaves a game. No matter if a game was played or not or
392  * whether
393  * the client is the host or not.
394  *
395  * \note as soon as this message is sent, the metaserver will list the client as not connected to
396  * any game.
397  * \note if the client that sends this message is the host of the game, the game will be
398  *       removed from list as well. However other clients connected to that game should send the
399  *       \ref IGPCMD_GAME_DISCONNECT themselves.
400  */
401 static const std::string IGPCMD_GAME_DISCONNECT = "GAME_DISCONNECT";
402 
403 /**
404  * Sent by the game hosting client to announce the start of the game. No payload.
405  * \note the hosting client will wait for the metaserver answer, to ensure the game is listed. If
406  * even
407  *       retries are not answered, the connection to the metaserver will be closed and a message
408  * shall be
409  *       sent in the newly started game.
410  *
411  * Sent by the metaserver to acknowledge the start without payload.
412  */
413 static const std::string IGPCMD_GAME_START = "GAME_START";
414 
415 #endif  // end of include guard: WL_NETWORK_INTERNET_GAMING_PROTOCOL_H
416