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) { |