diff --git a/lang/english.txt b/lang/english.txt index 8dad956696..6fb99f1c3d 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -1414,6 +1414,7 @@ STR_NETWORK_CLIENT_LIST :{WHITE}Client L STR_NETWORK_ERR_NOTAVAILABLE :{WHITE} No network devices found or compiled without ENABLE_NETWORK STR_NETWORK_ERR_NOSERVER :{WHITE} Could not find any network games STR_NETWORK_ERR_NOCONNECTION :{WHITE} The server didn't answer the request +STR_NETWORK_ERR_NEWGRF_MISMATCH :{WHITE} Could not connect due to NewGRF mismatch STR_NETWORK_ERR_DESYNC :{WHITE} Network-Game synchronisation failed STR_NETWORK_ERR_LOSTCONNECTION :{WHITE} Network-Game connection lost STR_NETWORK_ERR_SAVEGAMEERROR :{WHITE} Could not load savegame @@ -1435,6 +1436,7 @@ STR_NETWORK_ERR_CLIENT_DESYNC :desync error STR_NETWORK_ERR_CLIENT_SAVEGAME :could not load map STR_NETWORK_ERR_CLIENT_CONNECTION_LOST :connection lost STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR :protocol error +STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH :NewGRF mismatch STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED :not authorized STR_NETWORK_ERR_CLIENT_NOT_EXPECTED :received strange packet STR_NETWORK_ERR_CLIENT_WRONG_REVISION :wrong revision diff --git a/network.c b/network.c index 50496c91a6..a41b3a2cea 100644 --- a/network.c +++ b/network.c @@ -235,9 +235,10 @@ static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs) } switch (res) { - case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; - case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; - default: errorno = NETWORK_ERROR_GENERAL; break; + case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; + case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; + case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break; + default: errorno = NETWORK_ERROR_GENERAL; break; } // This means we fucked up and the server closed the connection if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && @@ -267,6 +268,7 @@ char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last) STR_NETWORK_ERR_CLIENT_SAVEGAME, STR_NETWORK_ERR_CLIENT_CONNECTION_LOST, STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR, + STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH, STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED, STR_NETWORK_ERR_CLIENT_NOT_EXPECTED, STR_NETWORK_ERR_CLIENT_WRONG_REVISION, diff --git a/network_client.c b/network_client.c index 298952a225..ee98d9c914 100644 --- a/network_client.c +++ b/network_client.c @@ -77,6 +77,18 @@ DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN) NetworkSend_Packet(p, MY_CLIENT); } +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED) +{ + // + // Packet: CLIENT_NEWGRFS_CHECKED + // Function: Tell the server that we have the required GRFs + // Data: + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_NEWGRFS_CHECKED); + NetworkSend_Packet(p, MY_CLIENT); +} + DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password) { // @@ -407,6 +419,39 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) return NETWORK_RECV_STATUS_SERVER_ERROR; } +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS) +{ + uint grf_count = NetworkRecv_uint8(MY_CLIENT, p); + NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY; + + /* Check all GRFs */ + for (; grf_count > 0; grf_count--) { + GRFConfig c; + const GRFConfig *f; + + NetworkRecv_GRFIdentifier(MY_CLIENT, p, &c); + + /* Check whether we know this GRF */ + f = FindGRFConfig(c.grfid, c.md5sum); + if (f == NULL) { + /* We do not know this GRF, bail out of initialization */ + char buf[sizeof(c.md5sum) * 2 + 1]; + md5sumToString(buf, lastof(buf), c.md5sum); + DEBUG(grf, 0)("NewGRF %08X not found; checksum %s", BSWAP32(c.grfid), buf); + ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH; + } + } + + if (ret == NETWORK_RECV_STATUS_OKAY) { + /* Start receiving the map */ + SEND_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED)(); + } else { + /* NewGRF mismatch, bail out */ + _switch_mode_errorstr = STR_NETWORK_ERR_NEWGRF_MISMATCH; + } + return ret; +} + DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD) { NetworkPasswordType type = NetworkRecv_uint8(MY_CLIENT, p); @@ -788,6 +833,8 @@ static NetworkClientPacket* const _network_client_packet[] = { RECEIVE_COMMAND(PACKET_SERVER_NEWGAME), RECEIVE_COMMAND(PACKET_SERVER_RCON), NULL, /*PACKET_CLIENT_RCON,*/ + RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS), + NULL, /*PACKET_CLIENT_NEWGRFS_CHECKED,*/ }; // If this fails, check the array above with network_data.h diff --git a/network_data.c b/network_data.c index 2af0f29760..0fec5139d6 100644 --- a/network_data.c +++ b/network_data.c @@ -293,6 +293,36 @@ void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t // (the line: 'p->size = (uint16)p->buffer[0];' and below) assert_compile(sizeof(PacketSize) == 2); + +/** + * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet + * @param p the packet to write the data to + * @param c the configuration to write the GRF ID and MD5 checksum from + */ +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) +{ + uint j; + NetworkSend_uint32(p, c->grfid); + for (j = 0; j < sizeof(c->md5sum); j++) { + NetworkSend_uint8 (p, c->md5sum[j]); + } +} + +/** + * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet + * @param p the packet to read the data from + * @param c the configuration to write the GRF ID and MD5 checksum to + */ +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c) +{ + uint j; + c->grfid = NetworkRecv_uint32(cs, p); + for (j = 0; j < sizeof(c->md5sum); j++) { + c->md5sum[j] = NetworkRecv_uint8(cs, p); + } +} + + Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status) { ssize_t res; diff --git a/network_data.h b/network_data.h index 16263c7762..589c8ca577 100644 --- a/network_data.h +++ b/network_data.h @@ -10,6 +10,8 @@ // Is the network enabled? #ifdef ENABLE_NETWORK +#include "newgrf_config.h" + #define SEND_MTU 1460 #define MAX_TEXT_MSG_LEN 1024 /* long long long long sentences :-) */ @@ -64,6 +66,7 @@ typedef enum { typedef enum { NETWORK_RECV_STATUS_OKAY, NETWORK_RECV_STATUS_DESYNC, + NETWORK_RECV_STATUS_NEWGRF_MISMATCH, ///< We did not have the required NewGRFs NETWORK_RECV_STATUS_SAVEGAME, NETWORK_RECV_STATUS_CONN_LOST, NETWORK_RECV_STATUS_MALFORMED_PACKET, @@ -81,6 +84,7 @@ typedef enum { NETWORK_ERROR_SAVEGAME_FAILED, NETWORK_ERROR_CONNECTION_LOST, NETWORK_ERROR_ILLEGAL_PACKET, + NETWORK_ERROR_NEWGRF_MISMATCH, // Signals from servers NETWORK_ERROR_NOT_AUTHORIZED, @@ -166,6 +170,8 @@ typedef enum { PACKET_SERVER_NEWGAME, PACKET_SERVER_RCON, PACKET_CLIENT_RCON, + PACKET_SERVER_CHECK_NEWGRFS, + PACKET_CLIENT_NEWGRFS_CHECKED, PACKET_END // Should ALWAYS be on the end of this list!! (period) } PacketType; @@ -217,6 +223,9 @@ uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet); void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size); Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c); +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c); + bool NetworkSend_Packets(NetworkClientState *cs); void NetworkExecuteCommand(CommandPacket *cp); void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp); diff --git a/network_server.c b/network_server.c index 758098d4ef..b01b8d4c95 100644 --- a/network_server.c +++ b/network_server.c @@ -180,6 +180,32 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, Netwo NetworkCloseClient(cs); } +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHECK_NEWGRFS)(NetworkClientState *cs) +{ + // + // Packet: PACKET_SERVER_CHECK_NEWGRFS + // Function: Sends info about the used GRFs to the client + // Data: + // uint8: Amount of GRFs + // And then for each GRF: + // uint32: GRF ID + // 16 * uint8: MD5 checksum of the GRF + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_CHECK_NEWGRFS); + const GRFConfig *c; + uint grf_count = 0; + + for (c = _grfconfig; c != NULL; c = c->next) grf_count++; + + NetworkSend_uint8 (p, grf_count); + for (c = _grfconfig; c != NULL; c = c->next) { + NetworkSend_GRFIdentifier(p, c); + } + + NetworkSend_Packet(p, cs); +} + DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type) { // @@ -567,6 +593,22 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO) SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs); } +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED) +{ + NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); + + /* We now want a password from the client else we do not allow him in! */ + if (_network_game_info.use_password) { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); + } else { + if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); + } else { + SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); + } + } +} + DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) { char name[NETWORK_CLIENT_NAME_LENGTH]; @@ -633,20 +675,14 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) ci->client_playas = playas; ci->client_lang = client_lang; - // We now want a password from the client - // else we do not allow him in! - if (_network_game_info.use_password) { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); - } else { - if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); - } else { - SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); - } - } - /* Make sure companies to which people try to join are not autocleaned */ if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0; + + if (_grfconfig == NULL) { + RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED)(cs, NULL); + } else { + SEND_COMMAND(PACKET_SERVER_CHECK_NEWGRFS)(cs); + } } DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD) @@ -1181,6 +1217,8 @@ static NetworkServerPacket* const _network_server_packet[] = { NULL, /*PACKET_SERVER_NEWGAME,*/ NULL, /*PACKET_SERVER_RCON,*/ RECEIVE_COMMAND(PACKET_CLIENT_RCON), + NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/ + RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED), }; // If this fails, check the array above with network_data.h diff --git a/network_udp.c b/network_udp.c index 5ff0483c03..be8078e564 100644 --- a/network_udp.c +++ b/network_udp.c @@ -45,34 +45,6 @@ static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* rec static NetworkClientState _udp_cs; -/** - * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet - * @param p the packet to write the data to - * @param c the configuration to write the GRF ID and MD5 checksum from - */ -static void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) -{ - uint j; - NetworkSend_uint32(p, c->grfid); - for (j = 0; j < sizeof(c->md5sum); j++) { - NetworkSend_uint8 (p, c->md5sum[j]); - } -} - -/** - * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet - * @param p the packet to read the data from - * @param c the configuration to write the GRF ID and MD5 checksum to - */ -static void NetworkRecv_GRFIdentifier(Packet *p, GRFConfig *c) -{ - uint j; - c->grfid = NetworkRecv_uint32(&_udp_cs, p); - for (j = 0; j < sizeof(c->md5sum); j++) { - c->md5sum[j] = NetworkRecv_uint8(&_udp_cs, p); - } -} - DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) { Packet *packet; @@ -173,7 +145,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) for (i = 0; i < num_grfs; i++) { c = calloc(1, sizeof(*c)); - NetworkRecv_GRFIdentifier(p, c); + NetworkRecv_GRFIdentifier(&_udp_cs, p, c); /* Find the matching GRF file */ f = FindGRFConfig(c->grfid, c->md5sum); @@ -457,7 +429,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS) GRFConfig c; const GRFConfig *f; - NetworkRecv_GRFIdentifier(p, &c); + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, c.md5sum); @@ -512,7 +484,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS) char name[NETWORK_GRF_NAME_LENGTH]; GRFConfig c; - NetworkRecv_GRFIdentifier(p, &c); + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); NetworkRecv_string(&_udp_cs, p, name, sizeof(name)); /* An empty name is not possible under normal circumstances