src/network/network_server.cpp
changeset 10685 955ddec7961e
parent 10684 7cc2278c2ac0
child 10703 2c998f3776d1
equal deleted inserted replaced
10684:7cc2278c2ac0 10685:955ddec7961e
   158 
   158 
   159 		NetworkGetClientName(client_name, sizeof(client_name), cs);
   159 		NetworkGetClientName(client_name, sizeof(client_name), cs);
   160 
   160 
   161 		DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
   161 		DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
   162 
   162 
   163 		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
   163 		NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
   164 
   164 
   165 		FOR_ALL_CLIENTS(new_cs) {
   165 		FOR_ALL_CLIENTS(new_cs) {
   166 			if (new_cs->status > STATUS_AUTH && new_cs != cs) {
   166 			if (new_cs->status > STATUS_AUTH && new_cs != cs) {
   167 				// Some errors we filter to a more general error. Clients don't have to know the real
   167 				// Some errors we filter to a more general error. Clients don't have to know the real
   168 				//  reason a joining failed.
   168 				//  reason a joining failed.
   777 		char client_name[NETWORK_CLIENT_NAME_LENGTH];
   777 		char client_name[NETWORK_CLIENT_NAME_LENGTH];
   778 		NetworkTCPSocketHandler *new_cs;
   778 		NetworkTCPSocketHandler *new_cs;
   779 
   779 
   780 		NetworkGetClientName(client_name, sizeof(client_name), cs);
   780 		NetworkGetClientName(client_name, sizeof(client_name), cs);
   781 
   781 
   782 		NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, client_name, "");
   782 		NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "");
   783 
   783 
   784 		// Mark the client as pre-active, and wait for an ACK
   784 		// Mark the client as pre-active, and wait for an ACK
   785 		//  so we know he is done loading and in sync with us
   785 		//  so we know he is done loading and in sync with us
   786 		cs->status = STATUS_PRE_ACTIVE;
   786 		cs->status = STATUS_PRE_ACTIVE;
   787 		NetworkHandleCommandQueue(cs);
   787 		NetworkHandleCommandQueue(cs);
   820 static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci)
   820 static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci)
   821 {
   821 {
   822 	byte flags = GetCommandFlags(cp->cmd);
   822 	byte flags = GetCommandFlags(cp->cmd);
   823 
   823 
   824 	if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) {
   824 	if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) {
   825 		IConsolePrintF(_icolour_err, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   825 		IConsolePrintF(CC_ERROR, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   826 		return false;
   826 		return false;
   827 	}
   827 	}
   828 
   828 
   829 	if (flags & CMD_OFFLINE) {
   829 	if (flags & CMD_OFFLINE) {
   830 		IConsolePrintF(_icolour_err, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   830 		IConsolePrintF(CC_ERROR, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   831 		return false;
   831 		return false;
   832 	}
   832 	}
   833 
   833 
   834 	if (cp->cmd != CMD_PLAYER_CTRL && !IsValidPlayer(cp->player) && ci->client_index != NETWORK_SERVER_INDEX) {
   834 	if (cp->cmd != CMD_PLAYER_CTRL && !IsValidPlayer(cp->player) && ci->client_index != NETWORK_SERVER_INDEX) {
   835 		IConsolePrintF(_icolour_err, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   835 		IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
   836 		return false;
   836 		return false;
   837 	}
   837 	}
   838 
   838 
   839 	return true;
   839 	return true;
   840 }
   840 }
   873 
   873 
   874 	ci = DEREF_CLIENT_INFO(cs);
   874 	ci = DEREF_CLIENT_INFO(cs);
   875 
   875 
   876 	/* Check if cp->cmd is valid */
   876 	/* Check if cp->cmd is valid */
   877 	if (!IsValidCommand(cp->cmd)) {
   877 	if (!IsValidCommand(cp->cmd)) {
   878 		IConsolePrintF(_icolour_err, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci));
   878 		IConsolePrintF(CC_ERROR, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci));
   879 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   879 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   880 		free(cp);
   880 		free(cp);
   881 		return;
   881 		return;
   882 	}
   882 	}
   883 
   883 
   890 	/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
   890 	/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
   891 	 * to match the player in the packet. If it doesn't, the client has done
   891 	 * to match the player in the packet. If it doesn't, the client has done
   892 	 * something pretty naughty (or a bug), and will be kicked
   892 	 * something pretty naughty (or a bug), and will be kicked
   893 	 */
   893 	 */
   894 	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) {
   894 	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) {
   895 		IConsolePrintF(_icolour_err, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
   895 		IConsolePrintF(CC_ERROR, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
   896 		               ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1);
   896 		               ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1);
   897 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
   897 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
   898 		free(cp);
   898 		free(cp);
   899 		return;
   899 		return;
   900 	}
   900 	}
   967 
   967 
   968 	GetNetworkErrorMsg(str, errorno, lastof(str));
   968 	GetNetworkErrorMsg(str, errorno, lastof(str));
   969 
   969 
   970 	DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
   970 	DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
   971 
   971 
   972 	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
   972 	NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
   973 
   973 
   974 	FOR_ALL_CLIENTS(new_cs) {
   974 	FOR_ALL_CLIENTS(new_cs) {
   975 		if (new_cs->status > STATUS_AUTH) {
   975 		if (new_cs->status > STATUS_AUTH) {
   976 			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
   976 			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
   977 		}
   977 		}
   996 
   996 
   997 	p->Recv_string(str, lengthof(str));
   997 	p->Recv_string(str, lengthof(str));
   998 
   998 
   999 	NetworkGetClientName(client_name, sizeof(client_name), cs);
   999 	NetworkGetClientName(client_name, sizeof(client_name), cs);
  1000 
  1000 
  1001 	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
  1001 	NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
  1002 
  1002 
  1003 	FOR_ALL_CLIENTS(new_cs) {
  1003 	FOR_ALL_CLIENTS(new_cs) {
  1004 		if (new_cs->status > STATUS_AUTH) {
  1004 		if (new_cs->status > STATUS_AUTH) {
  1005 			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str);
  1005 			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str);
  1006 		}
  1006 		}
  1050 		/* Are we sending to the server? */
  1050 		/* Are we sending to the server? */
  1051 		if (dest == NETWORK_SERVER_INDEX) {
  1051 		if (dest == NETWORK_SERVER_INDEX) {
  1052 			ci = NetworkFindClientInfoFromIndex(from_index);
  1052 			ci = NetworkFindClientInfoFromIndex(from_index);
  1053 			/* Display the text locally, and that is it */
  1053 			/* Display the text locally, and that is it */
  1054 			if (ci != NULL)
  1054 			if (ci != NULL)
  1055 				NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1055 				NetworkTextMessage(action, (ConsoleColour)GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1056 		} else {
  1056 		} else {
  1057 			/* Else find the client to send the message to */
  1057 			/* Else find the client to send the message to */
  1058 			FOR_ALL_CLIENTS(cs) {
  1058 			FOR_ALL_CLIENTS(cs) {
  1059 				if (cs->index == dest) {
  1059 				if (cs->index == dest) {
  1060 					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
  1060 					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
  1067 		if (from_index != dest) {
  1067 		if (from_index != dest) {
  1068 			if (from_index == NETWORK_SERVER_INDEX) {
  1068 			if (from_index == NETWORK_SERVER_INDEX) {
  1069 				ci = NetworkFindClientInfoFromIndex(from_index);
  1069 				ci = NetworkFindClientInfoFromIndex(from_index);
  1070 				ci_to = NetworkFindClientInfoFromIndex(dest);
  1070 				ci_to = NetworkFindClientInfoFromIndex(dest);
  1071 				if (ci != NULL && ci_to != NULL)
  1071 				if (ci != NULL && ci_to != NULL)
  1072 					NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg);
  1072 					NetworkTextMessage(action, (ConsoleColour)GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg);
  1073 			} else {
  1073 			} else {
  1074 				FOR_ALL_CLIENTS(cs) {
  1074 				FOR_ALL_CLIENTS(cs) {
  1075 					if (cs->index == from_index) {
  1075 					if (cs->index == from_index) {
  1076 						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg);
  1076 						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg);
  1077 						break;
  1077 						break;
  1095 		}
  1095 		}
  1096 
  1096 
  1097 		ci = NetworkFindClientInfoFromIndex(from_index);
  1097 		ci = NetworkFindClientInfoFromIndex(from_index);
  1098 		ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
  1098 		ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
  1099 		if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
  1099 		if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
  1100 			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1100 			NetworkTextMessage(action, (ConsoleColour)GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1101 			if (from_index == NETWORK_SERVER_INDEX) show_local = false;
  1101 			if (from_index == NETWORK_SERVER_INDEX) show_local = false;
  1102 			ci_to = ci_own;
  1102 			ci_to = ci_own;
  1103 		}
  1103 		}
  1104 
  1104 
  1105 		/* There is no such player */
  1105 		/* There is no such player */
  1110 			if (from_index == NETWORK_SERVER_INDEX) {
  1110 			if (from_index == NETWORK_SERVER_INDEX) {
  1111 				char name[NETWORK_NAME_LENGTH];
  1111 				char name[NETWORK_NAME_LENGTH];
  1112 				StringID str = IsValidPlayer(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
  1112 				StringID str = IsValidPlayer(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
  1113 				SetDParam(0, ci_to->client_playas);
  1113 				SetDParam(0, ci_to->client_playas);
  1114 				GetString(name, str, lastof(name));
  1114 				GetString(name, str, lastof(name));
  1115 				NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg);
  1115 				NetworkTextMessage(action, (ConsoleColour)GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg);
  1116 			} else {
  1116 			} else {
  1117 				FOR_ALL_CLIENTS(cs) {
  1117 				FOR_ALL_CLIENTS(cs) {
  1118 					if (cs->index == from_index) {
  1118 					if (cs->index == from_index) {
  1119 						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg);
  1119 						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg);
  1120 					}
  1120 					}
  1130 		FOR_ALL_CLIENTS(cs) {
  1130 		FOR_ALL_CLIENTS(cs) {
  1131 			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
  1131 			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
  1132 		}
  1132 		}
  1133 		ci = NetworkFindClientInfoFromIndex(from_index);
  1133 		ci = NetworkFindClientInfoFromIndex(from_index);
  1134 		if (ci != NULL)
  1134 		if (ci != NULL)
  1135 			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1135 			NetworkTextMessage(action, (ConsoleColour)GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
  1136 		break;
  1136 		break;
  1137 	}
  1137 	}
  1138 }
  1138 }
  1139 
  1139 
  1140 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
  1140 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
  1173 	if (cs->has_quit) return;
  1173 	if (cs->has_quit) return;
  1174 
  1174 
  1175 	if (ci != NULL) {
  1175 	if (ci != NULL) {
  1176 		// Display change
  1176 		// Display change
  1177 		if (NetworkFindName(client_name)) {
  1177 		if (NetworkFindName(client_name)) {
  1178 			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", client_name);
  1178 			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", client_name);
  1179 			ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name));
  1179 			ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name));
  1180 			NetworkUpdateClientInfo(ci->client_index);
  1180 			NetworkUpdateClientInfo(ci->client_index);
  1181 		}
  1181 		}
  1182 	}
  1182 	}
  1183 }
  1183 }
  1410 
  1410 
  1411 			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
  1411 			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
  1412 			if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') {
  1412 			if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') {
  1413 				/* Shut the company down */
  1413 				/* Shut the company down */
  1414 				DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL);
  1414 				DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL);
  1415 				IConsolePrintF(_icolour_def, "Auto-cleaned company #%d", p->index + 1);
  1415 				IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d", p->index + 1);
  1416 			}
  1416 			}
  1417 			/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
  1417 			/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
  1418 			if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') {
  1418 			if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') {
  1419 				/* Unprotect the company */
  1419 				/* Unprotect the company */
  1420 				_network_player_info[p->index].password[0] = '\0';
  1420 				_network_player_info[p->index].password[0] = '\0';
  1421 				IConsolePrintF(_icolour_def, "Auto-removed protection from company #%d", p->index+1);
  1421 				IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", p->index+1);
  1422 				_network_player_info[p->index].months_empty = 0;
  1422 				_network_player_info[p->index].months_empty = 0;
  1423 			}
  1423 			}
  1424 		} else {
  1424 		} else {
  1425 			/* It is not empty, reset the date */
  1425 			/* It is not empty, reset the date */
  1426 			_network_player_info[p->index].months_empty = 0;
  1426 			_network_player_info[p->index].months_empty = 0;
  1525 			int lag = NetworkCalculateLag(cs) / DAY_TICKS;
  1525 			int lag = NetworkCalculateLag(cs) / DAY_TICKS;
  1526 			if (lag > 0) {
  1526 			if (lag > 0) {
  1527 				if (lag > 3) {
  1527 				if (lag > 3) {
  1528 					// Client did still not report in after 4 game-day, drop him
  1528 					// Client did still not report in after 4 game-day, drop him
  1529 					//  (that is, the 3 of above, + 1 before any lag is counted)
  1529 					//  (that is, the 3 of above, + 1 before any lag is counted)
  1530 					IConsolePrintF(_icolour_err,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index);
  1530 					IConsolePrintF(CC_ERROR,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index);
  1531 					NetworkCloseClient(cs);
  1531 					NetworkCloseClient(cs);
  1532 					continue;
  1532 					continue;
  1533 				}
  1533 				}
  1534 
  1534 
  1535 				// Report once per time we detect the lag
  1535 				// Report once per time we detect the lag
  1536 				if (cs->lag_test == 0) {
  1536 				if (cs->lag_test == 0) {
  1537 					IConsolePrintF(_icolour_warn,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
  1537 					IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
  1538 					cs->lag_test = 1;
  1538 					cs->lag_test = 1;
  1539 				}
  1539 				}
  1540 			} else {
  1540 			} else {
  1541 				cs->lag_test = 0;
  1541 				cs->lag_test = 0;
  1542 			}
  1542 			}
  1543 		} else if (cs->status == STATUS_PRE_ACTIVE) {
  1543 		} else if (cs->status == STATUS_PRE_ACTIVE) {
  1544 			int lag = NetworkCalculateLag(cs);
  1544 			int lag = NetworkCalculateLag(cs);
  1545 			if (lag > _network_max_join_time) {
  1545 			if (lag > _network_max_join_time) {
  1546 				IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time);
  1546 				IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time);
  1547 				NetworkCloseClient(cs);
  1547 				NetworkCloseClient(cs);
  1548 			}
  1548 			}
  1549 		} else if (cs->status == STATUS_INACTIVE) {
  1549 		} else if (cs->status == STATUS_INACTIVE) {
  1550 			int lag = NetworkCalculateLag(cs);
  1550 			int lag = NetworkCalculateLag(cs);
  1551 			if (lag > 4 * DAY_TICKS) {
  1551 			if (lag > 4 * DAY_TICKS) {
  1552 				IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->index, 4 * DAY_TICKS);
  1552 				IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->index, 4 * DAY_TICKS);
  1553 				NetworkCloseClient(cs);
  1553 				NetworkCloseClient(cs);
  1554 			}
  1554 			}
  1555 		}
  1555 		}
  1556 
  1556 
  1557 		if (cs->status >= STATUS_PRE_ACTIVE) {
  1557 		if (cs->status >= STATUS_PRE_ACTIVE) {