(svn r8170) -Backport from trunk (r7984, r8118, r8167, r8168): 0.5
authorDarkvater
Tue, 16 Jan 2007 23:59:03 +0000
branch0.5
changeset 5407 e354823cde11
parent 5406 321f494e7b68
child 5408 1ed4ede56477
(svn r8170) -Backport from trunk (r7984, r8118, r8167, r8168):
- out-of-bounds read access on _clients array (Quark) (r7984)
- change the ordering of the network list (r8118)
- (FS#556): a network client crashes, due to a division by zero (r8167)
- ParseConnectionstring didn't use the port parameter if a player was also specified (r8168)
console_cmds.c
network.c
network_client.c
network_gui.c
--- a/console_cmds.c	Mon Jan 08 14:01:05 2007 +0000
+++ b/console_cmds.c	Tue Jan 16 23:59:03 2007 +0000
@@ -756,6 +756,11 @@
 	ParseConnectionString(&player, &port, ip);
 
 	IConsolePrintF(_icolour_def, "Connecting to %s...", ip);
+	if (port != NULL) {
+		rport = atoi(port);
+		IConsolePrintF(_icolour_def, "    port: %s", port);
+	}
+
 	if (player != NULL) {
 		_network_playas = atoi(player);
 		IConsolePrintF(_icolour_def, "    player-no: %d", _network_playas);
@@ -767,10 +772,6 @@
 			if (!IsValidPlayer(_network_playas)) return false;
 		}
 	}
-	if (port != NULL) {
-		rport = atoi(port);
-		IConsolePrintF(_icolour_def, "    port: %s", port);
-	}
 
 	NetworkClientConnectGame(ip, rport);
 
--- a/network.c	Mon Jan 08 14:01:05 2007 +0000
+++ b/network.c	Tue Jan 16 23:59:03 2007 +0000
@@ -82,7 +82,7 @@
 {
 	NetworkClientState *cs;
 
-	for (cs = _clients; cs != &_clients[MAX_CLIENT_INFO]; cs++) {
+	for (cs = _clients; cs != endof(_clients); cs++) {
 		if (cs->index == client_index) return cs;
 	}
 
@@ -513,24 +513,25 @@
 	return ip;
 }
 
-// Converts a string to ip/port/player
-//  Format: IP#player:port
-//
-// connection_string will be re-terminated to seperate out the hostname, and player and port will
-// be set to the player and port strings given by the user, inside the memory area originally
-// occupied by connection_string.
+/** Converts a string to ip/port/player
+ *  Format: IP#player:port
+ *
+ * connection_string will be re-terminated to seperate out the hostname, and player and port will
+ * be set to the player and port strings given by the user, inside the memory area originally
+ * occupied by connection_string. */
 void ParseConnectionString(const char **player, const char **port, char *connection_string)
 {
 	char *p;
 	for (p = connection_string; *p != '\0'; p++) {
-		if (*p == '#') {
-			*p = '\0';
-			*player = ++p;
-			while (IsValidChar(*p, CS_NUMERAL)) p++;
-			if (*p == '\0') break;
-		} else if (*p == ':') {
-			*port = p + 1;
-			*p = '\0';
+		switch (*p) {
+			case '#':
+				*player = p + 1;
+				*p = '\0';
+				break;
+			case ':':
+				*port = p + 1;
+				*p = '\0';
+				break;
 		}
 	}
 }
--- a/network_client.c	Mon Jan 08 14:01:05 2007 +0000
+++ b/network_client.c	Tue Jan 16 23:59:03 2007 +0000
@@ -467,9 +467,18 @@
 
 		_frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
 
-		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
 		_network_join_kbytes = 0;
 		_network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024;
+
+		/* If the network connection has been closed due to loss of connection
+		 * or when _network_join_kbytes_total is 0, the join status window will
+		 * do a division by zero. When the connection is lost, we just return
+		 * that. If kbytes_total is 0, the packet must be malformed as a
+		 * savegame less than 1 kilobyte is practically impossible. */
+		if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
+		if (_network_join_kbytes_total == 0) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
+		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
 		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 
 		// The first packet does not contain any more data
--- a/network_gui.c	Mon Jan 08 14:01:05 2007 +0000
+++ b/network_gui.c	Tue Jan 16 23:59:03 2007 +0000
@@ -141,10 +141,17 @@
 {
 	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
 	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
-	/* Reverse default as we are interested in compatible clients first */
-	int r = cmp2->info.compatible - cmp1->info.compatible;
 
+	/* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */
+	int r = (cmp1->info.server_revision[0] == '\0') - (cmp2->info.server_revision[0] == '\0');
+
+	/* Reverse default as we are interested in version-compatible clients first */
+	if (r == 0) r = cmp2->info.version_compatible - cmp1->info.version_compatible;
+	/* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */
+	if (r == 0) r = cmp2->info.compatible - cmp1->info.compatible;
+	/* Passworded servers should be below unpassworded servers */
 	if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password;
+	/* Finally sort on the name of the server */
 	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
 
 	return _internal_sort_order ? -r : r;
@@ -1409,7 +1416,7 @@
 				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, 14);
 				/* Fallthrough */
 			default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
-				progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
+				progress = 15 + _network_join_kbytes * (100 - 15) / (_network_join_kbytes_total+1);
 		}
 
 		/* Draw nice progress bar :) */