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