1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file network.cpp Base functions for networking support. */
9 
10 #include "../stdafx.h"
11 
12 #include "../strings_func.h"
13 #include "../command_func.h"
14 #include "../date_func.h"
15 #include "network_admin.h"
16 #include "network_client.h"
17 #include "network_query.h"
18 #include "network_server.h"
19 #include "network_content.h"
20 #include "network_udp.h"
21 #include "network_gamelist.h"
22 #include "network_base.h"
23 #include "network_coordinator.h"
24 #include "core/udp.h"
25 #include "core/host.h"
26 #include "network_gui.h"
27 #include "../console_func.h"
28 #include "../3rdparty/md5/md5.h"
29 #include "../core/random_func.hpp"
30 #include "../window_func.h"
31 #include "../company_func.h"
32 #include "../company_base.h"
33 #include "../landscape_type.h"
34 #include "../rev.h"
35 #include "../core/pool_func.hpp"
36 #include "../gfx_func.h"
37 #include "../error.h"
38 #include <charconv>
39 #include <sstream>
40 #include <iomanip>
41 
42 #include "../safeguards.h"
43 
44 #ifdef DEBUG_DUMP_COMMANDS
45 #include "../fileio_func.h"
46 /** When running the server till the wait point, run as fast as we can! */
47 bool _ddc_fastforward = true;
48 #endif /* DEBUG_DUMP_COMMANDS */
49 
50 /** Make sure both pools have the same size. */
51 static_assert(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE);
52 
53 /** The pool with client information. */
54 NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo");
55 INSTANTIATE_POOL_METHODS(NetworkClientInfo)
56 
57 bool _networking;         ///< are we in networking mode?
58 bool _network_server;     ///< network-server is active
59 bool _network_available;  ///< is network mode available?
60 bool _network_dedicated;  ///< are we a dedicated server?
61 bool _is_network_server;  ///< Does this client wants to be a network-server?
62 NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
63 ClientID _network_own_client_id;      ///< Our client identifier.
64 ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client.
65 uint8 _network_reconnect;             ///< Reconnect timeout
66 StringList _network_bind_list;        ///< The addresses to bind on.
67 StringList _network_host_list;        ///< The servers we know.
68 StringList _network_ban_list;         ///< The banned clients.
69 uint32 _frame_counter_server;         ///< The frame_counter of the server, if in network-mode
70 uint32 _frame_counter_max;            ///< To where we may go with our clients
71 uint32 _frame_counter;                ///< The current frame.
72 uint32 _last_sync_frame;              ///< Used in the server to store the last time a sync packet was sent to clients.
73 NetworkAddressList _broadcast_list;   ///< List of broadcast addresses.
74 uint32 _sync_seed_1;                  ///< Seed to compare during sync checks.
75 #ifdef NETWORK_SEND_DOUBLE_SEED
76 uint32 _sync_seed_2;                  ///< Second part of the seed.
77 #endif
78 uint32 _sync_frame;                   ///< The frame to perform the sync check.
79 bool _network_first_time;             ///< Whether we have finished joining or not.
80 CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies.
81 
82 static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH);
83 
84 /** The amount of clients connected */
85 byte _network_clients_connected = 0;
86 
87 /* Some externs / forwards */
88 extern void StateGameLoop();
89 
90 /**
91  * Return whether there is any client connected or trying to connect at all.
92  * @return whether we have any client activity
93  */
HasClients()94 bool HasClients()
95 {
96 	return !NetworkClientSocket::Iterate().empty();
97 }
98 
99 /**
100  * Basically a client is leaving us right now.
101  */
~NetworkClientInfo()102 NetworkClientInfo::~NetworkClientInfo()
103 {
104 	/* Delete the chat window, if you were chatting with this client. */
105 	InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id);
106 }
107 
108 /**
109  * Return the CI given it's client-identifier
110  * @param client_id the ClientID to search for
111  * @return return a pointer to the corresponding NetworkClientInfo struct or nullptr when not found
112  */
GetByClientID(ClientID client_id)113 /* static */ NetworkClientInfo *NetworkClientInfo::GetByClientID(ClientID client_id)
114 {
115 	for (NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
116 		if (ci->client_id == client_id) return ci;
117 	}
118 
119 	return nullptr;
120 }
121 
122 /**
123  * Return the client state given it's client-identifier
124  * @param client_id the ClientID to search for
125  * @return return a pointer to the corresponding NetworkClientSocket struct or nullptr when not found
126  */
GetByClientID(ClientID client_id)127 /* static */ ServerNetworkGameSocketHandler *ServerNetworkGameSocketHandler::GetByClientID(ClientID client_id)
128 {
129 	for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
130 		if (cs->client_id == client_id) return cs;
131 	}
132 
133 	return nullptr;
134 }
135 
NetworkSpectatorCount()136 byte NetworkSpectatorCount()
137 {
138 	byte count = 0;
139 
140 	for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
141 		if (ci->client_playas == COMPANY_SPECTATOR) count++;
142 	}
143 
144 	/* Don't count a dedicated server as spectator */
145 	if (_network_dedicated) count--;
146 
147 	return count;
148 }
149 
150 /**
151  * Change the company password of a given company.
152  * @param company_id ID of the company the password should be changed for.
153  * @param password The unhashed password we like to set ('*' or '' resets the password)
154  * @return The password.
155  */
NetworkChangeCompanyPassword(CompanyID company_id,std::string password)156 std::string NetworkChangeCompanyPassword(CompanyID company_id, std::string password)
157 {
158 	if (password.compare("*") == 0) password = "";
159 
160 	if (_network_server) {
161 		NetworkServerSetCompanyPassword(company_id, password, false);
162 	} else {
163 		NetworkClientSetCompanyPassword(password);
164 	}
165 
166 	return password;
167 }
168 
169 /**
170  * Hash the given password using server ID and game seed.
171  * @param password Password to hash.
172  * @param password_server_id Server ID.
173  * @param password_game_seed Game seed.
174  * @return The hashed password.
175  */
GenerateCompanyPasswordHash(const std::string & password,const std::string & password_server_id,uint32 password_game_seed)176 std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32 password_game_seed)
177 {
178 	if (password.empty()) return password;
179 
180 	size_t password_length = password.size();
181 	size_t password_server_id_length = password_server_id.size();
182 
183 	std::ostringstream salted_password;
184 	/* Add the password with the server's ID and game seed as the salt. */
185 	for (uint i = 0; i < NETWORK_SERVER_ID_LENGTH - 1; i++) {
186 		char password_char = (i < password_length ? password[i] : 0);
187 		char server_id_char = (i < password_server_id_length ? password_server_id[i] : 0);
188 		char seed_char = password_game_seed >> (i % 32);
189 		salted_password << (char)(password_char ^ server_id_char ^ seed_char); // Cast needed, otherwise interpreted as integer to format
190 	}
191 
192 	Md5 checksum;
193 	uint8 digest[16];
194 
195 	/* Generate the MD5 hash */
196 	std::string salted_password_string = salted_password.str();
197 	checksum.Append(salted_password_string.data(), salted_password_string.size());
198 	checksum.Finish(digest);
199 
200 	std::ostringstream hashed_password;
201 	hashed_password << std::hex << std::setfill('0');
202 	for (int di = 0; di < 16; di++) hashed_password << std::setw(2) << (int)digest[di]; // Cast needed, otherwise interpreted as character to add
203 
204 	return hashed_password.str();
205 }
206 
207 /**
208  * Check if the company we want to join requires a password.
209  * @param company_id id of the company we want to check the 'passworded' flag for.
210  * @return true if the company requires a password.
211  */
NetworkCompanyIsPassworded(CompanyID company_id)212 bool NetworkCompanyIsPassworded(CompanyID company_id)
213 {
214 	return HasBit(_network_company_passworded, company_id);
215 }
216 
217 /* This puts a text-message to the console, or in the future, the chat-box,
218  *  (to keep it all a bit more general)
219  * If 'self_send' is true, this is the client who is sending the message */
NetworkTextMessage(NetworkAction action,TextColour colour,bool self_send,const std::string & name,const std::string & str,int64 data,const std::string & data_str)220 void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const std::string &name, const std::string &str, int64 data, const std::string &data_str)
221 {
222 	StringID strid;
223 	switch (action) {
224 		case NETWORK_ACTION_SERVER_MESSAGE:
225 			/* Ignore invalid messages */
226 			strid = STR_NETWORK_SERVER_MESSAGE;
227 			colour = CC_DEFAULT;
228 			break;
229 		case NETWORK_ACTION_COMPANY_SPECTATOR:
230 			colour = CC_DEFAULT;
231 			strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE;
232 			break;
233 		case NETWORK_ACTION_COMPANY_JOIN:
234 			colour = CC_DEFAULT;
235 			strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN;
236 			break;
237 		case NETWORK_ACTION_COMPANY_NEW:
238 			colour = CC_DEFAULT;
239 			strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW;
240 			break;
241 		case NETWORK_ACTION_JOIN:
242 			/* Show the Client ID for the server but not for the client. */
243 			strid = _network_server ? STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :  STR_NETWORK_MESSAGE_CLIENT_JOINED;
244 			break;
245 		case NETWORK_ACTION_LEAVE:          strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; break;
246 		case NETWORK_ACTION_NAME_CHANGE:    strid = STR_NETWORK_MESSAGE_NAME_CHANGE; break;
247 		case NETWORK_ACTION_GIVE_MONEY:     strid = STR_NETWORK_MESSAGE_GIVE_MONEY; break;
248 		case NETWORK_ACTION_CHAT_COMPANY:   strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break;
249 		case NETWORK_ACTION_CHAT_CLIENT:    strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT  : STR_NETWORK_CHAT_CLIENT;  break;
250 		case NETWORK_ACTION_KICKED:         strid = STR_NETWORK_MESSAGE_KICKED; break;
251 		case NETWORK_ACTION_EXTERNAL_CHAT:  strid = STR_NETWORK_CHAT_EXTERNAL; break;
252 		default:                            strid = STR_NETWORK_CHAT_ALL; break;
253 	}
254 
255 	char message[1024];
256 	SetDParamStr(0, name);
257 	SetDParamStr(1, str);
258 	SetDParam(2, data);
259 	SetDParamStr(3, data_str);
260 
261 	/* All of these strings start with "***". These characters are interpreted as both left-to-right and
262 	 * right-to-left characters depending on the context. As the next text might be an user's name, the
263 	 * user name's characters will influence the direction of the "***" instead of the language setting
264 	 * of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
265 	char *msg_ptr = message + Utf8Encode(message, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
266 	GetString(msg_ptr, strid, lastof(message));
267 
268 	Debug(desync, 1, "msg: {:08x}; {:02x}; {}", _date, _date_fract, message);
269 	IConsolePrint(colour, message);
270 	NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
271 }
272 
273 /* Calculate the frame-lag of a client */
NetworkCalculateLag(const NetworkClientSocket * cs)274 uint NetworkCalculateLag(const NetworkClientSocket *cs)
275 {
276 	int lag = cs->last_frame_server - cs->last_frame;
277 	/* This client has missed their ACK packet after 1 DAY_TICKS..
278 	 *  so we increase their lag for every frame that passes!
279 	 * The packet can be out by a max of _net_frame_freq */
280 	if (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) {
281 		lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq);
282 	}
283 	return lag;
284 }
285 
286 
287 /* There was a non-recoverable error, drop back to the main menu with a nice
288  *  error */
ShowNetworkError(StringID error_string)289 void ShowNetworkError(StringID error_string)
290 {
291 	_switch_mode = SM_MENU;
292 	ShowErrorMessage(error_string, INVALID_STRING_ID, WL_CRITICAL);
293 }
294 
295 /**
296  * Retrieve the string id of an internal error number
297  * @param err NetworkErrorCode
298  * @return the StringID
299  */
GetNetworkErrorMsg(NetworkErrorCode err)300 StringID GetNetworkErrorMsg(NetworkErrorCode err)
301 {
302 	/* List of possible network errors, used by
303 	 * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */
304 	static const StringID network_error_strings[] = {
305 		STR_NETWORK_ERROR_CLIENT_GENERAL,
306 		STR_NETWORK_ERROR_CLIENT_DESYNC,
307 		STR_NETWORK_ERROR_CLIENT_SAVEGAME,
308 		STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST,
309 		STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR,
310 		STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH,
311 		STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED,
312 		STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED,
313 		STR_NETWORK_ERROR_CLIENT_WRONG_REVISION,
314 		STR_NETWORK_ERROR_CLIENT_NAME_IN_USE,
315 		STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD,
316 		STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH,
317 		STR_NETWORK_ERROR_CLIENT_KICKED,
318 		STR_NETWORK_ERROR_CLIENT_CHEATER,
319 		STR_NETWORK_ERROR_CLIENT_SERVER_FULL,
320 		STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS,
321 		STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD,
322 		STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER,
323 		STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
324 		STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
325 		STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME,
326 	};
327 	static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
328 
329 	if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
330 
331 	return network_error_strings[err];
332 }
333 
334 /**
335  * Handle the pause mode change so we send the right messages to the chat.
336  * @param prev_mode The previous pause mode.
337  * @param changed_mode The pause mode that got changed.
338  */
NetworkHandlePauseChange(PauseMode prev_mode,PauseMode changed_mode)339 void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
340 {
341 	if (!_networking) return;
342 
343 	switch (changed_mode) {
344 		case PM_PAUSED_NORMAL:
345 		case PM_PAUSED_JOIN:
346 		case PM_PAUSED_GAME_SCRIPT:
347 		case PM_PAUSED_ACTIVE_CLIENTS:
348 		case PM_PAUSED_LINK_GRAPH: {
349 			bool changed = ((_pause_mode == PM_UNPAUSED) != (prev_mode == PM_UNPAUSED));
350 			bool paused = (_pause_mode != PM_UNPAUSED);
351 			if (!paused && !changed) return;
352 
353 			StringID str;
354 			if (!changed) {
355 				int i = -1;
356 
357 				if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED)         SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL);
358 				if ((_pause_mode & PM_PAUSED_JOIN) != PM_UNPAUSED)           SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS);
359 				if ((_pause_mode & PM_PAUSED_GAME_SCRIPT) != PM_UNPAUSED)    SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT);
360 				if ((_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS);
361 				if ((_pause_mode & PM_PAUSED_LINK_GRAPH) != PM_UNPAUSED)     SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH);
362 				str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i;
363 			} else {
364 				switch (changed_mode) {
365 					case PM_PAUSED_NORMAL:         SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL); break;
366 					case PM_PAUSED_JOIN:           SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); break;
367 					case PM_PAUSED_GAME_SCRIPT:    SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT); break;
368 					case PM_PAUSED_ACTIVE_CLIENTS: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); break;
369 					case PM_PAUSED_LINK_GRAPH:     SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH); break;
370 					default: NOT_REACHED();
371 				}
372 				str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED;
373 			}
374 
375 			NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, "", GetString(str));
376 			break;
377 		}
378 
379 		default:
380 			return;
381 	}
382 }
383 
384 
385 /**
386  * Helper function for the pause checkers. If pause is true and the
387  * current pause mode isn't set the game will be paused, if it it false
388  * and the pause mode is set the game will be unpaused. In the other
389  * cases nothing happens to the pause state.
390  * @param pause whether we'd like to pause
391  * @param pm the mode which we would like to pause with
392  */
CheckPauseHelper(bool pause,PauseMode pm)393 static void CheckPauseHelper(bool pause, PauseMode pm)
394 {
395 	if (pause == ((_pause_mode & pm) != PM_UNPAUSED)) return;
396 
397 	DoCommandP(0, pm, pause ? 1 : 0, CMD_PAUSE);
398 }
399 
400 /**
401  * Counts the number of active clients connected.
402  * It has to be in STATUS_ACTIVE and not a spectator
403  * @return number of active clients
404  */
NetworkCountActiveClients()405 static uint NetworkCountActiveClients()
406 {
407 	uint count = 0;
408 
409 	for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
410 		if (cs->status != NetworkClientSocket::STATUS_ACTIVE) continue;
411 		if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue;
412 		count++;
413 	}
414 
415 	return count;
416 }
417 
418 /**
419  * Check if the minimum number of active clients has been reached and pause or unpause the game as appropriate
420  */
CheckMinActiveClients()421 static void CheckMinActiveClients()
422 {
423 	if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
424 			!_network_dedicated ||
425 			(_settings_client.network.min_active_clients == 0 && (_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) == PM_UNPAUSED)) {
426 		return;
427 	}
428 	CheckPauseHelper(NetworkCountActiveClients() < _settings_client.network.min_active_clients, PM_PAUSED_ACTIVE_CLIENTS);
429 }
430 
431 /**
432  * Checks whether there is a joining client
433  * @return true iff one client is joining (but not authorizing)
434  */
NetworkHasJoiningClient()435 static bool NetworkHasJoiningClient()
436 {
437 	for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
438 		if (cs->status >= NetworkClientSocket::STATUS_AUTHORIZED && cs->status < NetworkClientSocket::STATUS_ACTIVE) return true;
439 	}
440 
441 	return false;
442 }
443 
444 /**
445  * Check whether we should pause on join
446  */
CheckPauseOnJoin()447 static void CheckPauseOnJoin()
448 {
449 	if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
450 			(!_settings_client.network.pause_on_join && (_pause_mode & PM_PAUSED_JOIN) == PM_UNPAUSED)) {
451 		return;
452 	}
453 	CheckPauseHelper(NetworkHasJoiningClient(), PM_PAUSED_JOIN);
454 }
455 
456 /**
457  * Parse the company part ("#company" postfix) of a connecting string.
458  * @param connection_string The string with the connection data.
459  * @param company_id        The company ID to set, if available.
460  * @return A std::string_view into the connection string without the company part.
461  */
ParseCompanyFromConnectionString(const std::string & connection_string,CompanyID * company_id)462 std::string_view ParseCompanyFromConnectionString(const std::string &connection_string, CompanyID *company_id)
463 {
464 	std::string_view ip = connection_string;
465 	if (company_id == nullptr) return ip;
466 
467 	size_t offset = ip.find_last_of('#');
468 	if (offset != std::string::npos) {
469 		std::string_view company_string = ip.substr(offset + 1);
470 		ip = ip.substr(0, offset);
471 
472 		uint8 company_value;
473 		auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
474 		if (err == std::errc()) {
475 			if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
476 				if (company_value > MAX_COMPANIES || company_value == 0) {
477 					*company_id = COMPANY_SPECTATOR;
478 				} else {
479 					/* "#1" means the first company, which has index 0. */
480 					*company_id = (CompanyID)(company_value - 1);
481 				}
482 			} else {
483 				*company_id = (CompanyID)company_value;
484 			}
485 		}
486 	}
487 
488 	return ip;
489 }
490 
491 /**
492  * Converts a string to ip/port/company
493  *  Format: IP:port#company
494  *
495  * Returns the IP part as a string view into the passed string. This view is
496  * valid as long the passed connection string is valid. If there is no port
497  * present in the connection string, the port reference will not be touched.
498  * When there is no company ID present in the connection string or company_id
499  * is nullptr, then company ID will not be touched.
500  *
501  * @param connection_string The string with the connection data.
502  * @param port              The port reference to set.
503  * @param company_id        The company ID to set, if available.
504  * @return A std::string_view into the connection string with the (IP) address part.
505  */
ParseFullConnectionString(const std::string & connection_string,uint16 & port,CompanyID * company_id)506 std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id)
507 {
508 	std::string_view ip = ParseCompanyFromConnectionString(connection_string, company_id);
509 
510 	size_t port_offset = ip.find_last_of(':');
511 	size_t ipv6_close = ip.find_last_of(']');
512 	if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) {
513 		std::string_view port_string = ip.substr(port_offset + 1);
514 		ip = ip.substr(0, port_offset);
515 		std::from_chars(port_string.data(), port_string.data() + port_string.size(), port);
516 	}
517 	return ip;
518 }
519 
520 /**
521  * Normalize a connection string. That is, ensure there is a port in the string.
522  * @param connection_string The connection string to normalize.
523  * @param default_port The port to use if none is given.
524  * @return The normalized connection string.
525  */
NormalizeConnectionString(const std::string & connection_string,uint16 default_port)526 std::string NormalizeConnectionString(const std::string &connection_string, uint16 default_port)
527 {
528 	uint16 port = default_port;
529 	std::string_view ip = ParseFullConnectionString(connection_string, port);
530 	return std::string(ip) + ":" + std::to_string(port);
531 }
532 
533 /**
534  * Convert a string containing either "hostname" or "hostname:ip" to a
535  * NetworkAddress.
536  *
537  * @param connection_string The string to parse.
538  * @param default_port The default port to set port to if not in connection_string.
539  * @return A valid NetworkAddress of the parsed information.
540  */
ParseConnectionString(const std::string & connection_string,uint16 default_port)541 NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port)
542 {
543 	uint16 port = default_port;
544 	std::string_view ip = ParseFullConnectionString(connection_string, port);
545 	return NetworkAddress(ip, port);
546 }
547 
548 /**
549  * Handle the accepting of a connection to the server.
550  * @param s The socket of the new connection.
551  * @param address The address of the peer.
552  */
AcceptConnection(SOCKET s,const NetworkAddress & address)553 /* static */ void ServerNetworkGameSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address)
554 {
555 	/* Register the login */
556 	_network_clients_connected++;
557 
558 	ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s);
559 	cs->client_address = address; // Save the IP of the client
560 
561 	InvalidateWindowData(WC_CLIENT_LIST, 0);
562 }
563 
564 /**
565  * Resets the pools used for network clients, and the admin pool if needed.
566  * @param close_admins Whether the admin pool has to be cleared as well.
567  */
InitializeNetworkPools(bool close_admins=true)568 static void InitializeNetworkPools(bool close_admins = true)
569 {
570 	PoolBase::Clean(PT_NCLIENT | (close_admins ? PT_NADMIN : PT_NONE));
571 }
572 
573 /**
574  * Close current connections.
575  * @param close_admins Whether the admin connections have to be closed as well.
576  */
NetworkClose(bool close_admins)577 void NetworkClose(bool close_admins)
578 {
579 	if (_network_server) {
580 		if (close_admins) {
581 			for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::Iterate()) {
582 				as->CloseConnection(true);
583 			}
584 		}
585 
586 		for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
587 			cs->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
588 		}
589 		ServerNetworkGameSocketHandler::CloseListeners();
590 		ServerNetworkAdminSocketHandler::CloseListeners();
591 
592 		_network_coordinator_client.CloseConnection();
593 	} else {
594 		if (MyClient::my_client != nullptr) {
595 			MyClient::SendQuit();
596 			MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
597 		}
598 
599 		_network_coordinator_client.CloseAllConnections();
600 	}
601 
602 	TCPConnecter::KillAll();
603 
604 	_networking = false;
605 	_network_server = false;
606 
607 	NetworkFreeLocalCommandQueue();
608 
609 	delete[] _network_company_states;
610 	_network_company_states = nullptr;
611 
612 	InitializeNetworkPools(close_admins);
613 }
614 
615 /* Initializes the network (cleans sockets and stuff) */
NetworkInitialize(bool close_admins=true)616 static void NetworkInitialize(bool close_admins = true)
617 {
618 	InitializeNetworkPools(close_admins);
619 
620 	_sync_frame = 0;
621 	_network_first_time = true;
622 
623 	_network_reconnect = 0;
624 }
625 
626 /** Non blocking connection to query servers for their game info. */
627 class TCPQueryConnecter : TCPServerConnecter {
628 private:
629 	std::string connection_string;
630 
631 public:
TCPQueryConnecter(const std::string & connection_string)632 	TCPQueryConnecter(const std::string &connection_string) : TCPServerConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
633 
OnFailure()634 	void OnFailure() override
635 	{
636 		NetworkGameList *item = NetworkGameListAddItem(connection_string);
637 		item->status = NGLS_OFFLINE;
638 		item->refreshing = false;
639 
640 		UpdateNetworkGameWindow();
641 	}
642 
OnConnect(SOCKET s)643 	void OnConnect(SOCKET s) override
644 	{
645 		QueryNetworkGameSocketHandler::QueryServer(s, this->connection_string);
646 	}
647 };
648 
649 /**
650  * Query a server to fetch the game-info.
651  * @param connection_string the address to query.
652  */
NetworkQueryServer(const std::string & connection_string)653 void NetworkQueryServer(const std::string &connection_string)
654 {
655 	if (!_network_available) return;
656 
657 	/* Mark the entry as refreshing, so the GUI can show the refresh is pending. */
658 	NetworkGameList *item = NetworkGameListAddItem(connection_string);
659 	item->refreshing = true;
660 
661 	new TCPQueryConnecter(connection_string);
662 }
663 
664 /**
665  * Validates an address entered as a string and adds the server to
666  * the list. If you use this function, the games will be marked
667  * as manually added.
668  * @param connection_string The IP:port of the server to add.
669  * @param manually Whether the enter should be marked as manual added.
670  * @param never_expire Whether the entry can expire (removed when no longer found in the public listing).
671  * @return The entry on the game list.
672  */
NetworkAddServer(const std::string & connection_string,bool manually,bool never_expire)673 NetworkGameList *NetworkAddServer(const std::string &connection_string, bool manually, bool never_expire)
674 {
675 	if (connection_string.empty()) return nullptr;
676 
677 	/* Ensure the item already exists in the list */
678 	NetworkGameList *item = NetworkGameListAddItem(connection_string);
679 	if (item->info.server_name.empty()) {
680 		ClearGRFConfigList(&item->info.grfconfig);
681 		item->info.server_name = connection_string;
682 
683 		UpdateNetworkGameWindow();
684 
685 		NetworkQueryServer(connection_string);
686 	}
687 
688 	if (manually) item->manually = true;
689 	if (never_expire) item->version = INT32_MAX;
690 
691 	return item;
692 }
693 
694 /**
695  * Get the addresses to bind to.
696  * @param addresses the list to write to.
697  * @param port the port to bind to.
698  */
GetBindAddresses(NetworkAddressList * addresses,uint16 port)699 void GetBindAddresses(NetworkAddressList *addresses, uint16 port)
700 {
701 	for (const auto &iter : _network_bind_list) {
702 		addresses->emplace_back(iter.c_str(), port);
703 	}
704 
705 	/* No address, so bind to everything. */
706 	if (addresses->size() == 0) {
707 		addresses->emplace_back("", port);
708 	}
709 }
710 
711 /* Generates the list of manually added hosts from NetworkGameList and
712  * dumps them into the array _network_host_list. This array is needed
713  * by the function that generates the config file. */
NetworkRebuildHostList()714 void NetworkRebuildHostList()
715 {
716 	_network_host_list.clear();
717 
718 	for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) {
719 		if (item->manually) _network_host_list.emplace_back(item->connection_string);
720 	}
721 }
722 
723 /** Non blocking connection create to actually connect to servers */
724 class TCPClientConnecter : TCPServerConnecter {
725 private:
726 	std::string connection_string;
727 
728 public:
TCPClientConnecter(const std::string & connection_string)729 	TCPClientConnecter(const std::string &connection_string) : TCPServerConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
730 
OnFailure()731 	void OnFailure() override
732 	{
733 		ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION);
734 	}
735 
OnConnect(SOCKET s)736 	void OnConnect(SOCKET s) override
737 	{
738 		_networking = true;
739 		new ClientNetworkGameSocketHandler(s, this->connection_string);
740 		IConsoleCmdExec("exec scripts/on_client.scr 0");
741 		NetworkClient_Connected();
742 	}
743 };
744 
745 /**
746  * Join a client to the server at with the given connection string.
747  * The default for the passwords is \c nullptr. When the server or company needs a
748  * password and none is given, the user is asked to enter the password in the GUI.
749  * This function will return false whenever some information required to join is not
750  * correct such as the company number or the client's name, or when there is not
751  * networking avalabile at all. If the function returns false the connection with
752  * the existing server is not disconnected.
753  * It will return true when it starts the actual join process, i.e. when it
754  * actually shows the join status window.
755  *
756  * @param connection_string     The IP address, port and company number to join as.
757  * @param default_company       The company number to join as when none is given.
758  * @param join_server_password  The password for the server.
759  * @param join_company_password The password for the company.
760  * @return Whether the join has started.
761  */
NetworkClientConnectGame(const std::string & connection_string,CompanyID default_company,const std::string & join_server_password,const std::string & join_company_password)762 bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const std::string &join_server_password, const std::string &join_company_password)
763 {
764 	CompanyID join_as = default_company;
765 	std::string resolved_connection_string = ServerAddress::Parse(connection_string, NETWORK_DEFAULT_PORT, &join_as).connection_string;
766 
767 	if (!_network_available) return false;
768 	if (!NetworkValidateOurClientName()) return false;
769 
770 	_network_join.connection_string = resolved_connection_string;
771 	_network_join.company = join_as;
772 	_network_join.server_password = join_server_password;
773 	_network_join.company_password = join_company_password;
774 
775 	if (_game_mode == GM_MENU) {
776 		/* From the menu we can immediately continue with the actual join. */
777 		NetworkClientJoinGame();
778 	} else {
779 		/* When already playing a game, first go back to the main menu. This
780 		 * disconnects the user from the current game, meaning we can safely
781 		 * load in the new. After all, there is little point in continueing to
782 		 * play on a server if we are connecting to another one.
783 		 */
784 		_switch_mode = SM_JOIN_GAME;
785 	}
786 	return true;
787 }
788 
789 /**
790  * Actually perform the joining to the server. Use #NetworkClientConnectGame
791  * when you want to connect to a specific server/company. This function
792  * assumes _network_join is already fully set up.
793  */
NetworkClientJoinGame()794 void NetworkClientJoinGame()
795 {
796 	NetworkDisconnect();
797 	NetworkInitialize();
798 
799 	_settings_client.network.last_joined = _network_join.connection_string;
800 	_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
801 	ShowJoinStatusWindow();
802 
803 	new TCPClientConnecter(_network_join.connection_string);
804 }
805 
NetworkInitGameInfo()806 static void NetworkInitGameInfo()
807 {
808 	FillStaticNetworkServerGameInfo();
809 	/* The server is a client too */
810 	_network_game_info.clients_on = _network_dedicated ? 0 : 1;
811 
812 	/* There should be always space for the server. */
813 	assert(NetworkClientInfo::CanAllocateItem());
814 	NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
815 	ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST;
816 
817 	ci->client_name = _settings_client.network.client_name;
818 }
819 
820 /**
821  * Trim the given server name in place, i.e. remove leading and trailing spaces.
822  * After the trim check whether the server name is not empty.
823  * When the server name is empty a GUI error message is shown telling the
824  * user to set the servername and this function returns false.
825  *
826  * @param server_name The server name to validate. It will be trimmed of leading
827  *                    and trailing spaces.
828  * @return True iff the server name is valid.
829  */
NetworkValidateServerName(std::string & server_name)830 bool NetworkValidateServerName(std::string &server_name)
831 {
832 	StrTrimInPlace(server_name);
833 	if (!server_name.empty()) return true;
834 
835 	ShowErrorMessage(STR_NETWORK_ERROR_BAD_SERVER_NAME, INVALID_STRING_ID, WL_ERROR);
836 	return false;
837 }
838 
839 /**
840  * Check whether the client and server name are set, for a dedicated server and if not set them to some default
841  * value and tell the user to change this as soon as possible.
842  * If the saved name is the default value, then the user is told to override  this value too.
843  * This is only meant dedicated servers, as for the other servers the GUI ensures a name has been entered.
844  */
CheckClientAndServerName()845 static void CheckClientAndServerName()
846 {
847 	static const std::string fallback_client_name = "Unnamed Client";
848 	StrTrimInPlace(_settings_client.network.client_name);
849 	if (_settings_client.network.client_name.empty() || _settings_client.network.client_name.compare(fallback_client_name) == 0) {
850 		Debug(net, 1, "No \"client_name\" has been set, using \"{}\" instead. Please set this now using the \"name <new name>\" command", fallback_client_name);
851 		_settings_client.network.client_name = fallback_client_name;
852 	}
853 
854 	static const std::string fallback_server_name = "Unnamed Server";
855 	StrTrimInPlace(_settings_client.network.server_name);
856 	if (_settings_client.network.server_name.empty() || _settings_client.network.server_name.compare(fallback_server_name) == 0) {
857 		Debug(net, 1, "No \"server_name\" has been set, using \"{}\" instead. Please set this now using the \"server_name <new name>\" command", fallback_server_name);
858 		_settings_client.network.server_name = fallback_server_name;
859 	}
860 }
861 
NetworkServerStart()862 bool NetworkServerStart()
863 {
864 	if (!_network_available) return false;
865 
866 	/* Call the pre-scripts */
867 	IConsoleCmdExec("exec scripts/pre_server.scr 0");
868 	if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
869 
870 	/* Check for the client and server names to be set, but only after the scripts had a chance to set them.*/
871 	if (_network_dedicated) CheckClientAndServerName();
872 
873 	NetworkDisconnect(false, false);
874 	NetworkInitialize(false);
875 	NetworkUDPInitialize();
876 	Debug(net, 5, "Starting listeners for clients");
877 	if (!ServerNetworkGameSocketHandler::Listen(_settings_client.network.server_port)) return false;
878 
879 	/* Only listen for admins when the password isn't empty. */
880 	if (!_settings_client.network.admin_password.empty()) {
881 		Debug(net, 5, "Starting listeners for admins");
882 		if (!ServerNetworkAdminSocketHandler::Listen(_settings_client.network.server_admin_port)) return false;
883 	}
884 
885 	/* Try to start UDP-server */
886 	Debug(net, 5, "Starting listeners for incoming server queries");
887 	NetworkUDPServerListen();
888 
889 	_network_company_states = new NetworkCompanyState[MAX_COMPANIES];
890 	_network_server = true;
891 	_networking = true;
892 	_frame_counter = 0;
893 	_frame_counter_server = 0;
894 	_frame_counter_max = 0;
895 	_last_sync_frame = 0;
896 	_network_own_client_id = CLIENT_ID_SERVER;
897 
898 	_network_clients_connected = 0;
899 	_network_company_passworded = 0;
900 
901 	NetworkInitGameInfo();
902 
903 	if (_settings_client.network.server_game_type != SERVER_GAME_TYPE_LOCAL) {
904 		_network_coordinator_client.Register();
905 	}
906 
907 	/* execute server initialization script */
908 	IConsoleCmdExec("exec scripts/on_server.scr 0");
909 	/* if the server is dedicated ... add some other script */
910 	if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
911 
912 	/* welcome possibly still connected admins - this can only happen on a dedicated server. */
913 	if (_network_dedicated) ServerNetworkAdminSocketHandler::WelcomeAll();
914 
915 	return true;
916 }
917 
918 /* The server is rebooting...
919  * The only difference with NetworkDisconnect, is the packets that is sent */
NetworkReboot()920 void NetworkReboot()
921 {
922 	if (_network_server) {
923 		for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
924 			cs->SendNewGame();
925 			cs->SendPackets();
926 		}
927 
928 		for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::IterateActive()) {
929 			as->SendNewGame();
930 			as->SendPackets();
931 		}
932 	}
933 
934 	/* For non-dedicated servers we have to kick the admins as we are not
935 	 * certain that we will end up in a new network game. */
936 	NetworkClose(!_network_dedicated);
937 }
938 
939 /**
940  * We want to disconnect from the host/clients.
941  * @param blocking whether to wait till everything has been closed.
942  * @param close_admins Whether the admin sockets need to be closed as well.
943  */
NetworkDisconnect(bool blocking,bool close_admins)944 void NetworkDisconnect(bool blocking, bool close_admins)
945 {
946 	if (_network_server) {
947 		for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
948 			cs->SendShutdown();
949 			cs->SendPackets();
950 		}
951 
952 		if (close_admins) {
953 			for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::IterateActive()) {
954 				as->SendShutdown();
955 				as->SendPackets();
956 			}
957 		}
958 	}
959 
960 	CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
961 
962 	NetworkClose(close_admins);
963 
964 	/* Reinitialize the UDP stack, i.e. close all existing connections. */
965 	NetworkUDPInitialize();
966 }
967 
968 /**
969  * The setting server_game_type was updated; possibly we need to take some
970  * action.
971  */
NetworkUpdateServerGameType()972 void NetworkUpdateServerGameType()
973 {
974 	if (!_networking) return;
975 
976 	switch (_settings_client.network.server_game_type) {
977 		case SERVER_GAME_TYPE_LOCAL:
978 			_network_coordinator_client.CloseConnection();
979 			break;
980 
981 		case SERVER_GAME_TYPE_INVITE_ONLY:
982 		case SERVER_GAME_TYPE_PUBLIC:
983 			_network_coordinator_client.Register();
984 			break;
985 
986 		default:
987 			NOT_REACHED();
988 	}
989 }
990 
991 /**
992  * Receives something from the network.
993  * @return true if everything went fine, false when the connection got closed.
994  */
NetworkReceive()995 static bool NetworkReceive()
996 {
997 	if (_network_server) {
998 		ServerNetworkAdminSocketHandler::Receive();
999 		return ServerNetworkGameSocketHandler::Receive();
1000 	} else {
1001 		return ClientNetworkGameSocketHandler::Receive();
1002 	}
1003 }
1004 
1005 /* This sends all buffered commands (if possible) */
NetworkSend()1006 static void NetworkSend()
1007 {
1008 	if (_network_server) {
1009 		ServerNetworkAdminSocketHandler::Send();
1010 		ServerNetworkGameSocketHandler::Send();
1011 	} else {
1012 		ClientNetworkGameSocketHandler::Send();
1013 	}
1014 }
1015 
1016 /**
1017  * We have to do some (simple) background stuff that runs normally,
1018  * even when we are not in multiplayer. For example stuff needed
1019  * for finding servers or downloading content.
1020  */
NetworkBackgroundLoop()1021 void NetworkBackgroundLoop()
1022 {
1023 	_network_content_client.SendReceive();
1024 	_network_coordinator_client.SendReceive();
1025 	TCPConnecter::CheckCallbacks();
1026 	NetworkHTTPSocketHandler::HTTPReceive();
1027 	QueryNetworkGameSocketHandler::SendReceive();
1028 
1029 	NetworkBackgroundUDPLoop();
1030 }
1031 
1032 /* The main loop called from ttd.c
1033  *  Here we also have to do StateGameLoop if needed! */
NetworkGameLoop()1034 void NetworkGameLoop()
1035 {
1036 	if (!_networking) return;
1037 
1038 	if (!NetworkReceive()) return;
1039 
1040 	if (_network_server) {
1041 		/* Log the sync state to check for in-syncedness of replays. */
1042 		if (_date_fract == 0) {
1043 			/* We don't want to log multiple times if paused. */
1044 			static Date last_log;
1045 			if (last_log != _date) {
1046 				Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", _date, _date_fract, _random.state[0], _random.state[1]);
1047 				last_log = _date;
1048 			}
1049 		}
1050 
1051 #ifdef DEBUG_DUMP_COMMANDS
1052 		/* Loading of the debug commands from -ddesync>=1 */
1053 		static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
1054 		static Date next_date = 0;
1055 		static uint32 next_date_fract;
1056 		static CommandPacket *cp = nullptr;
1057 		static bool check_sync_state = false;
1058 		static uint32 sync_state[2];
1059 		if (f == nullptr && next_date == 0) {
1060 			Debug(desync, 0, "Cannot open commands.log");
1061 			next_date = 1;
1062 		}
1063 
1064 		while (f != nullptr && !feof(f)) {
1065 			if (_date == next_date && _date_fract == next_date_fract) {
1066 				if (cp != nullptr) {
1067 					NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->cmd & ~CMD_FLAGS_MASK, nullptr, cp->text, cp->company);
1068 					Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:06x}; {:08x}; {:08x}; {:08x}; \"{}\" ({})", _date, _date_fract, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->cmd, cp->text, GetCommandName(cp->cmd));
1069 					delete cp;
1070 					cp = nullptr;
1071 				}
1072 				if (check_sync_state) {
1073 					if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
1074 						Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", _date, _date_fract);
1075 					} else {
1076 						Debug(desync, 0, "Sync check: {:08x}; {:02x}; mismatch expected {{{:08x}, {:08x}}}, got {{{:08x}, {:08x}}}",
1077 									_date, _date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
1078 						NOT_REACHED();
1079 					}
1080 					check_sync_state = false;
1081 				}
1082 			}
1083 
1084 			if (cp != nullptr || check_sync_state) break;
1085 
1086 			char buff[4096];
1087 			if (fgets(buff, lengthof(buff), f) == nullptr) break;
1088 
1089 			char *p = buff;
1090 			/* Ignore the "[date time] " part of the message */
1091 			if (*p == '[') {
1092 				p = strchr(p, ']');
1093 				if (p == nullptr) break;
1094 				p += 2;
1095 			}
1096 
1097 			if (strncmp(p, "cmd: ", 5) == 0
1098 #ifdef DEBUG_FAILED_DUMP_COMMANDS
1099 				|| strncmp(p, "cmdf: ", 6) == 0
1100 #endif
1101 				) {
1102 				p += 5;
1103 				if (*p == ' ') p++;
1104 				cp = new CommandPacket();
1105 				int company;
1106 				char buffer[128];
1107 				int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %x; \"%127[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, buffer);
1108 				cp->text = buffer;
1109 				/* There are 8 pieces of data to read, however the last is a
1110 				 * string that might or might not exist. Ignore it if that
1111 				 * string misses because in 99% of the time it's not used. */
1112 				assert(ret == 8 || ret == 7);
1113 				cp->company = (CompanyID)company;
1114 			} else if (strncmp(p, "join: ", 6) == 0) {
1115 				/* Manually insert a pause when joining; this way the client can join at the exact right time. */
1116 				int ret = sscanf(p + 6, "%x; %x", &next_date, &next_date_fract);
1117 				assert(ret == 2);
1118 				Debug(desync, 0, "Injecting pause for join at {:08x}:{:02x}; please join when paused", next_date, next_date_fract);
1119 				cp = new CommandPacket();
1120 				cp->company = COMPANY_SPECTATOR;
1121 				cp->cmd = CMD_PAUSE;
1122 				cp->p1 = PM_PAUSED_NORMAL;
1123 				cp->p2 = 1;
1124 				_ddc_fastforward = false;
1125 			} else if (strncmp(p, "sync: ", 6) == 0) {
1126 				int ret = sscanf(p + 6, "%x; %x; %x; %x", &next_date, &next_date_fract, &sync_state[0], &sync_state[1]);
1127 				assert(ret == 4);
1128 				check_sync_state = true;
1129 			} else if (strncmp(p, "msg: ", 5) == 0 || strncmp(p, "client: ", 8) == 0 ||
1130 						strncmp(p, "load: ", 6) == 0 || strncmp(p, "save: ", 6) == 0) {
1131 				/* A message that is not very important to the log playback, but part of the log. */
1132 #ifndef DEBUG_FAILED_DUMP_COMMANDS
1133 			} else if (strncmp(p, "cmdf: ", 6) == 0) {
1134 				Debug(desync, 0, "Skipping replay of failed command: {}", p + 6);
1135 #endif
1136 			} else {
1137 				/* Can't parse a line; what's wrong here? */
1138 				Debug(desync, 0, "Trying to parse: {}", p);
1139 				NOT_REACHED();
1140 			}
1141 		}
1142 		if (f != nullptr && feof(f)) {
1143 			Debug(desync, 0, "End of commands.log");
1144 			fclose(f);
1145 			f = nullptr;
1146 		}
1147 #endif /* DEBUG_DUMP_COMMANDS */
1148 		if (_frame_counter >= _frame_counter_max) {
1149 			/* Only check for active clients just before we're going to send out
1150 			 * the commands so we don't send multiple pause/unpause commands when
1151 			 * the frame_freq is more than 1 tick. Same with distributing commands. */
1152 			CheckPauseOnJoin();
1153 			CheckMinActiveClients();
1154 			NetworkDistributeCommands();
1155 		}
1156 
1157 		bool send_frame = false;
1158 
1159 		/* We first increase the _frame_counter */
1160 		_frame_counter++;
1161 		/* Update max-frame-counter */
1162 		if (_frame_counter > _frame_counter_max) {
1163 			_frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
1164 			send_frame = true;
1165 		}
1166 
1167 		NetworkExecuteLocalCommandQueue();
1168 
1169 		/* Then we make the frame */
1170 		StateGameLoop();
1171 
1172 		_sync_seed_1 = _random.state[0];
1173 #ifdef NETWORK_SEND_DOUBLE_SEED
1174 		_sync_seed_2 = _random.state[1];
1175 #endif
1176 
1177 		NetworkServer_Tick(send_frame);
1178 	} else {
1179 		/* Client */
1180 
1181 		/* Make sure we are at the frame were the server is (quick-frames) */
1182 		if (_frame_counter_server > _frame_counter) {
1183 			/* Run a number of frames; when things go bad, get out. */
1184 			while (_frame_counter_server > _frame_counter) {
1185 				if (!ClientNetworkGameSocketHandler::GameLoop()) return;
1186 			}
1187 		} else {
1188 			/* Else, keep on going till _frame_counter_max */
1189 			if (_frame_counter_max > _frame_counter) {
1190 				/* Run one frame; if things went bad, get out. */
1191 				if (!ClientNetworkGameSocketHandler::GameLoop()) return;
1192 			}
1193 		}
1194 	}
1195 
1196 	NetworkSend();
1197 }
1198 
NetworkGenerateServerId()1199 static void NetworkGenerateServerId()
1200 {
1201 	Md5 checksum;
1202 	uint8 digest[16];
1203 	char hex_output[16 * 2 + 1];
1204 	char coding_string[NETWORK_NAME_LENGTH];
1205 	int di;
1206 
1207 	seprintf(coding_string, lastof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID");
1208 
1209 	/* Generate the MD5 hash */
1210 	checksum.Append((const uint8*)coding_string, strlen(coding_string));
1211 	checksum.Finish(digest);
1212 
1213 	for (di = 0; di < 16; ++di) {
1214 		seprintf(hex_output + di * 2, lastof(hex_output), "%02x", digest[di]);
1215 	}
1216 
1217 	/* _settings_client.network.network_id is our id */
1218 	_settings_client.network.network_id = hex_output;
1219 }
1220 
1221 class TCPNetworkDebugConnecter : TCPConnecter {
1222 private:
1223 	std::string connection_string;
1224 
1225 public:
TCPNetworkDebugConnecter(const std::string & connection_string)1226 	TCPNetworkDebugConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT), connection_string(connection_string) {}
1227 
OnFailure()1228 	void OnFailure() override
1229 	{
1230 		Debug(net, 0, "Failed to open connection to {} for redirecting Debug()", this->connection_string);
1231 	}
1232 
OnConnect(SOCKET s)1233 	void OnConnect(SOCKET s) override
1234 	{
1235 		Debug(net, 3, "Redirecting Debug() to {}", this->connection_string);
1236 
1237 		extern SOCKET _debug_socket;
1238 		_debug_socket = s;
1239 	}
1240 };
1241 
NetworkStartDebugLog(const std::string & connection_string)1242 void NetworkStartDebugLog(const std::string &connection_string)
1243 {
1244 	new TCPNetworkDebugConnecter(connection_string);
1245 }
1246 
1247 /** This tries to launch the network for a given OS */
NetworkStartUp()1248 void NetworkStartUp()
1249 {
1250 	Debug(net, 3, "Starting network");
1251 
1252 	/* Network is available */
1253 	_network_available = NetworkCoreInitialize();
1254 	_network_dedicated = false;
1255 
1256 	/* Generate an server id when there is none yet */
1257 	if (_settings_client.network.network_id.empty()) NetworkGenerateServerId();
1258 
1259 	_network_game_info = {};
1260 
1261 	NetworkInitialize();
1262 	NetworkUDPInitialize();
1263 	Debug(net, 3, "Network online, multiplayer available");
1264 	NetworkFindBroadcastIPs(&_broadcast_list);
1265 }
1266 
1267 /** This shuts the network down */
NetworkShutDown()1268 void NetworkShutDown()
1269 {
1270 	NetworkDisconnect(true);
1271 	NetworkUDPClose();
1272 
1273 	Debug(net, 3, "Shutting down network");
1274 
1275 	_network_available = false;
1276 
1277 	NetworkCoreShutdown();
1278 }
1279 
1280 #ifdef __EMSCRIPTEN__
1281 extern "C" {
1282 
em_openttd_add_server(const char * connection_string)1283 void CDECL em_openttd_add_server(const char *connection_string)
1284 {
1285 	NetworkAddServer(connection_string, false, true);
1286 }
1287 
1288 }
1289 #endif
1290