From 7a081330e4d54a94ade401405c0494af2ca0c55f Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 13 Jul 2013 10:13:55 +0000 Subject: [PATCH] (svn r25599) [1.3] -Backport from trunk: - Fix: [Admin] End-of-rcon data could not be determined reliably for any rcon command [FS#5643] (r25598, r25588, r25587) - Fix: [Content] When the server closed the connection, the client would for eternity try to read a packet and never timeout making it impossible to reconnect [FS#5635] (r25597) - Fix: [Script] Changing the script difficulty level in-game would also change the settings using the default even though they were not allowed to change in-game [FS#5644] (r25592) - Fix: [Admin] Ensure that sent and received length of json strings are the same [FS#5646] (r25590, r25589) - Fix: [Squirrel] Stack overflow did not show an error, due to the stack to throw the error already being full [FS#5320] (r25585) --- bin/baseset/no_music.obm | 2 +- bin/baseset/no_sound.obs | 2 +- bin/baseset/orig_dos.obg | 2 +- bin/baseset/orig_dos.obs | 2 +- bin/baseset/orig_dos_de.obg | 2 +- bin/baseset/orig_win.obg | 2 +- bin/baseset/orig_win.obm | 2 +- bin/baseset/orig_win.obs | 2 +- docs/admin_network.txt | 10 +++++- src/3rdparty/squirrel/squirrel/sqvm.cpp | 1 + src/3rdparty/squirrel/squirrel/sqvm.h | 5 ++- src/ai/ai_core.cpp | 1 + src/game/game_core.cpp | 2 ++ src/network/core/config.h | 46 ++++++++++++------------- src/network/core/tcp_admin.cpp | 6 ++++ src/network/core/tcp_admin.h | 27 +++++++++++++++ src/network/core/tcp_content.cpp | 10 ++++-- src/network/core/tcp_content.h | 2 +- src/network/network_admin.cpp | 46 ++++++++++++++++++++++--- src/network/network_admin.h | 3 ++ src/network/network_content.cpp | 6 ++-- src/script/script_config.cpp | 9 +++++ src/script/script_config.hpp | 10 ++++++ 23 files changed, 156 insertions(+), 44 deletions(-) diff --git a/bin/baseset/no_music.obm b/bin/baseset/no_music.obm index 5fa9f6d436..3b4a64c4fd 100644 --- a/bin/baseset/no_music.obm +++ b/bin/baseset/no_music.obm @@ -31,7 +31,7 @@ description.hu_HU = Zenei alapcsomag zene nélkül. description.id_ID = Paket musik tanpa musik sungguhan. description.is_IS = Tónlistarpakki sem er í raun án tónlistar. description.it_IT = Un pacchetto musicale non contenente alcuna musica. -description.ja_JP = 音楽が無いミュージックパック +description.ja_JP = 空の音楽パック description.ko_KR = 실제 음악이 없는 음악 목록입니다. description.lt_LT = Muzikos pakas be muzikos. description.nb_NO = En musikkpakke uten noe musikk. diff --git a/bin/baseset/no_sound.obs b/bin/baseset/no_sound.obs index c66f8a85c4..328f0ea9bd 100644 --- a/bin/baseset/no_sound.obs +++ b/bin/baseset/no_sound.obs @@ -31,7 +31,7 @@ description.hu_HU = Hang alapcsomag hangok nélkül. description.id_ID = Paket efek suara tanpa suara apapun. description.is_IS = Hljóðpakki án hljóðs. description.it_IT = Un pacchetto sonoro non contenente alcun suono. -description.ja_JP = 音楽が無いミュージックパック +description.ja_JP = 空の効果音パック description.ko_KR = 아무런 효과음도 없는 효과음 팩입니다. description.lt_LT = Garsų pakas be jokių garsų. description.nb_NO = En lydpakke uten noen lyder. diff --git a/bin/baseset/orig_dos.obg b/bin/baseset/orig_dos.obg index 3980b0a093..b124084e25 100644 --- a/bin/baseset/orig_dos.obg +++ b/bin/baseset/orig_dos.obg @@ -32,7 +32,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának grafik description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS. description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione DOS. -description.ja_JP = オリジナルDOS『トランスポートタイクンデラックス』版画像 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 도스 에디션의 그래픽입니다. description.lt_LT = Originali Transport Tycoon Deluxe DOS leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS. diff --git a/bin/baseset/orig_dos.obs b/bin/baseset/orig_dos.obs index 0a331b4c03..e01eb7a42a 100644 --- a/bin/baseset/orig_dos.obs +++ b/bin/baseset/orig_dos.obs @@ -31,7 +31,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának hangjai description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi DOS. description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe DOS útgáfunni. description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione DOS. -description.ja_JP = オリジナル DOS 『トランスポートタイクンデラックス』版音楽 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (DOS) description.ko_KR = 오리지널 트랜스포트 타이쿤 도스 에디션의 효과음입니다. description.lt_LT = Originalūs Transport Tycoon Deluxe DOS leidimo garsai. description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for DOS. diff --git a/bin/baseset/orig_dos_de.obg b/bin/baseset/orig_dos_de.obg index 5198ae4341..3c72253f61 100644 --- a/bin/baseset/orig_dos_de.obg +++ b/bin/baseset/orig_dos_de.obg @@ -32,7 +32,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS (német) verziójána description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS (Jerman). description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS (þýsku) útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe (tedesco), edizione DOS. -description.ja_JP = オリジナルDOS『トランスポートタイクンデラックス』ドイツ語版 画像 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS・ドイツ版) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 도스 에디션(독일)의 그래픽입니다. description.lt_LT = Originali Transport Tycoon Deluxe DOS (Vokiečių) leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS (tysk). diff --git a/bin/baseset/orig_win.obg b/bin/baseset/orig_win.obg index fef8998e15..fbcd6b2f0d 100644 --- a/bin/baseset/orig_win.obg +++ b/bin/baseset/orig_win.obg @@ -32,7 +32,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának gra description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione Windows. -description.ja_JP = オリジナルウィンドーズ『トランスポートタイクンデラックス』版 画像 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도우 에디션의 그래픽입니다. description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for Windows. diff --git a/bin/baseset/orig_win.obm b/bin/baseset/orig_win.obm index 919ec1e88b..8fa81a64a3 100644 --- a/bin/baseset/orig_win.obm +++ b/bin/baseset/orig_win.obm @@ -31,7 +31,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának zen description.id_ID = Musik pengiring orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega tónlistin úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Musica originale di Transport Tycoon Deluxe, edizione Windows. -description.ja_JP = オリジナルウィンドーズ『トランスポートタイクンデラックス』版音楽 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 音楽 (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도우 에디션의 음악입니다. description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo muzika. description.nb_NO = Original musikk fra Transport Tycoon Deluxe for Windows. diff --git a/bin/baseset/orig_win.obs b/bin/baseset/orig_win.obs index 2d536eb8c1..d8387bb0d5 100644 --- a/bin/baseset/orig_win.obs +++ b/bin/baseset/orig_win.obs @@ -31,7 +31,7 @@ description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának han description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione Windows. -description.ja_JP = オリジナルウィンドーズ『トランスポートタイクンデラックス』版音楽 +description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도우 에디션의 효과음입니다. description.lt_LT = Originalūs Transport Tycoon Deluxe Windows leidimo garsai. description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for Windows. diff --git a/docs/admin_network.txt b/docs/admin_network.txt index 1922a4d6d9..904f3ca204 100644 --- a/docs/admin_network.txt +++ b/docs/admin_network.txt @@ -150,7 +150,8 @@ Table of contents Note: No additional authentication is required for rcon commands. - The server will reply with a ADMIN_PACKET_SERVER_RCON packet. Applications + The server will reply with one or more ADMIN_PACKET_SERVER_RCON packets. + Finally an ADMIN_PACKET_ADMIN_RCON_END packet will be sent. Applications will not receive the answer twice if they have asked for the AdminUpdateType ADMIN_UPDATE_CONSOLE, as the result is not printed on the servers console (just like clients rcon commands). @@ -160,6 +161,13 @@ Table of contents Chat from the server itself will only be sent to the admin network when it was not sent from the admin network. + Note that when content is queried or updated via rcon, the processing + happens asynchronously. But the ADMIN_PACKET_ADMIN_RCON_END packet is sent + already right after the content is requested as there's no immediate output. + Thus other packages and the output of content rcon command may be sent at + an arbitrary later time, mixing into the output of other console activity, + e.g. also of possible subsequent other rcon commands sent. + 5.0) Sending chat ---- ------------ diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index 9041c79862..c8f4db674a 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -107,6 +107,7 @@ SQVM::SQVM(SQSharedState *ss) _errorhandler = _null_; _debughook = _null_; _can_suspend = false; + _in_stackoverflow = false; _ops_till_suspend = 0; ci = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h index 4b922c370f..d272d152e7 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.h +++ b/src/3rdparty/squirrel/squirrel/sqvm.h @@ -170,6 +170,7 @@ public: SQBool _can_suspend; SQInteger _ops_till_suspend; + SQBool _in_stackoverflow; bool ShouldSuspend() { @@ -200,8 +201,10 @@ inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v-> #define PUSH_CALLINFO(v,nci){ \ if(v->_callsstacksize == v->_alloccallsstacksize) { \ - if (v->_callsstacksize > 65535) {\ + if (v->_callsstacksize > 65535 && !v->_in_stackoverflow) {\ + v->_in_stackoverflow = true; \ v->Raise_Error(_SC("stack overflow"));\ + v->CallErrorHandler(v->_lasterror);\ return false;\ }\ v->GrowCallStack(); \ diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index 8ad3e67df8..3f4381b0c5 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -47,6 +47,7 @@ /* Load default data and store the name in the settings */ config->Change(info->GetName(), -1, false, true); } + config->AnchorUnchangeableSettings(); Backup cur_company(_current_company, company, FILE_LINE); Company *c = Company::Get(company); diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index e1a21872aa..9fd47a4c8b 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -71,6 +71,8 @@ GameInfo *info = config->GetInfo(); if (info == NULL) return; + config->AnchorUnchangeableSettings(); + Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); diff --git a/src/network/core/config.h b/src/network/core/config.h index cbe4f5d74d..93f75e3776 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -25,33 +25,33 @@ static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas"; /** Message sent to the masterserver to 'identify' this client as OpenTTD */ static const char * const NETWORK_MASTER_SERVER_WELCOME_MESSAGE = "OpenTTDRegister"; -static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP) -static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) -static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP) -static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP) -static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network -static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) +static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP) +static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) +static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP) +static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP) +static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network +static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) -static const uint16 SEND_MTU = 1460; ///< Number of bytes we can pack in a single packet +static const uint16 SEND_MTU = 1460; ///< Number of bytes we can pack in a single packet -static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? -static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use? -static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? -static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What version of master-server-protocol do we use? +static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? +static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use? +static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? +static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What version of master-server-protocol do we use? -static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' -static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' -static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0' -static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0' -static const uint NETWORK_REVISION_LENGTH = 15; ///< The maximum length of the revision, in bytes including '\0' -static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH) -static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0' -static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0' -static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0' -static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = 1450; ///< The maximum length of a gamescript json string, in bytes including '\0' -static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0' +static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' +static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' +static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0' +static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0' +static const uint NETWORK_REVISION_LENGTH = 15; ///< The maximum length of the revision, in bytes including '\0' +static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH) +static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0' +static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0' +static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0' +static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = SEND_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than SEND_MTU including header (3 bytes) +static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0' -static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF +static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF /** * Maximum number of GRFs that can be sent. diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index 0271598830..0a3153319b 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -61,6 +61,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) case ADMIN_PACKET_ADMIN_CHAT: return this->Receive_ADMIN_CHAT(p); case ADMIN_PACKET_ADMIN_RCON: return this->Receive_ADMIN_RCON(p); case ADMIN_PACKET_ADMIN_GAMESCRIPT: return this->Receive_ADMIN_GAMESCRIPT(p); + case ADMIN_PACKET_ADMIN_PING: return this->Receive_ADMIN_PING(p); case ADMIN_PACKET_SERVER_FULL: return this->Receive_SERVER_FULL(p); case ADMIN_PACKET_SERVER_BANNED: return this->Receive_SERVER_BANNED(p); @@ -87,6 +88,8 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) case ADMIN_PACKET_SERVER_CONSOLE: return this->Receive_SERVER_CONSOLE(p); case ADMIN_PACKET_SERVER_CMD_NAMES: return this->Receive_SERVER_CMD_NAMES(p); case ADMIN_PACKET_SERVER_CMD_LOGGING: return this->Receive_SERVER_CMD_LOGGING(p); + case ADMIN_PACKET_SERVER_RCON_END: return this->Receive_SERVER_RCON_END(p); + case ADMIN_PACKET_SERVER_PONG: return this->Receive_SERVER_PONG(p); default: if (this->HasClientQuit()) { @@ -136,6 +139,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) { ret NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_CHAT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_RCON); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_GAMESCRIPT); } +NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_PING); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_FULL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_FULL); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_BANNED); } @@ -162,5 +166,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON(Packet *p) { re NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CONSOLE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CONSOLE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_NAMES(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_NAMES); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_LOGGING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_LOGGING); } +NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON_END(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON_END); } +NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PONG(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PONG); } #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index 932c3af42a..72c2e1160e 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -33,6 +33,7 @@ enum PacketAdminType { ADMIN_PACKET_ADMIN_CHAT, ///< The admin sends a chat message to be distributed. ADMIN_PACKET_ADMIN_RCON, ///< The admin sends a remote console command. ADMIN_PACKET_ADMIN_GAMESCRIPT, ///< The admin sends a JSON string for the GameScript. + ADMIN_PACKET_ADMIN_PING, ///< The admin sends a ping to the server, expecting a ping-reply (PONG) packet. ADMIN_PACKET_SERVER_FULL = 100, ///< The server tells the admin it cannot accept the admin. ADMIN_PACKET_SERVER_BANNED, ///< The server tells the admin it is banned. @@ -60,6 +61,8 @@ enum PacketAdminType { ADMIN_PACKET_SERVER_CMD_NAMES, ///< The server sends out the names of the DoCommands to the admins. ADMIN_PACKET_SERVER_CMD_LOGGING, ///< The server gives the admin copies of incoming command packets. ADMIN_PACKET_SERVER_GAMESCRIPT, ///< The server gives the admin information from the GameScript in JSON. + ADMIN_PACKET_SERVER_RCON_END, ///< The server indicates that the remote console command has completed. + ADMIN_PACKET_SERVER_PONG, ///< The server replies to a ping request from the admin. INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. }; @@ -180,6 +183,14 @@ protected: */ virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p); + /** + * Ping the server, requiring the server to reply with a pong packet. + * uint32 Integer value to pass to the server, which is quoted in the reply. + * @param p The packet that was just received. + * @return The state the network should have. + */ + virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p); + /** * The server is full (connection gets closed). * @param p The packet that was just received. @@ -454,6 +465,22 @@ protected: */ virtual NetworkRecvStatus Receive_SERVER_CMD_LOGGING(Packet *p); + /** + * Send a ping-reply (pong) to the admin that sent us the ping packet. + * uint32 Integer identifier - should be the same as read from the admins ping packet. + * @param p The packet that was just received. + * @return The state the network should have. + */ + virtual NetworkRecvStatus Receive_SERVER_PONG(Packet *p); + + /** + * Notify the admin connection that the rcon command has finished. + * string The command as requested by the admin connection. + * @param p The packet that was just received. + * @return The state the network should have. + */ + virtual NetworkRecvStatus Receive_SERVER_RCON_END(Packet *p); + NetworkRecvStatus HandlePacket(Packet *p); public: NetworkRecvStatus CloseConnection(bool error = true); diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index 164f8de3c3..d4bc820d12 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -189,8 +189,9 @@ bool NetworkContentSocketHandler::HandlePacket(Packet *p) /** * Receive a packet at TCP level + * @return Whether at least one packet was received. */ -void NetworkContentSocketHandler::ReceivePackets() +bool NetworkContentSocketHandler::ReceivePackets() { /* * We read only a few of the packets. This as receiving packets can be expensive @@ -212,12 +213,15 @@ void NetworkContentSocketHandler::ReceivePackets() * What arbitrary number to choose is the ultimate question though. */ Packet *p; - int i = 42; + static const int MAX_PACKETS_TO_RECEIVE = 42; + int i = MAX_PACKETS_TO_RECEIVE; while (--i != 0 && (p = this->ReceivePacket()) != NULL) { bool cont = this->HandlePacket(p); delete p; - if (!cont) return; + if (!cont) return true; } + + return i != MAX_PACKETS_TO_RECEIVE - 1; } diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h index 5ad6ac5f4a..a506439da9 100644 --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -206,7 +206,7 @@ public: /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkContentSocketHandler() { this->Close(); } - void ReceivePackets(); + bool ReceivePackets(); }; #ifndef OPENTTD_MSU diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index a78f0c8695..0c060b7556 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -480,6 +480,20 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action return NETWORK_RECV_STATUS_OKAY; } +/** + * Send a notification indicating the rcon command has completed. + * @param command The original command sent. + */ +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const char *command) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON_END); + + p->Send_string(command); + this->SendPacket(p); + + return NETWORK_RECV_STATUS_OKAY; +} + /** * Send the reply of an rcon command. * @param colour The colour of the text. @@ -509,7 +523,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p) _redirect_console_to_admin = this->index; IConsoleCmdExec(command); _redirect_console_to_admin = INVALID_ADMIN_ID; - return NETWORK_RECV_STATUS_OKAY; + return this->SendRconEnd(command); } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p) @@ -526,6 +540,17 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Pack return NETWORK_RECV_STATUS_OKAY; } +NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p) +{ + if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); + + uint32 d1 = p->Recv_uint32(); + + DEBUG(net, 2, "[admin] Ping from '%s' (%s): '%d'", this->admin_name, this->admin_version, d1); + + return this->SendPong(d1); +} + /** * Send console output of other clients. * @param origin The origin of the string. @@ -554,10 +579,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const char *origi */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const char *json) { - /* At the moment we cannot transmit anything larger than MTU. So the string - * has to be no longer than the length of the json + '\0' + 3 bytes of the - * packet header. */ - if (strlen(json) + 1 + 3 >= SEND_MTU) return NETWORK_RECV_STATUS_OKAY; + /* At the moment we cannot transmit anything larger than MTU. So we limit + * the maximum amount of json data that can be sent. Account also for + * the trailing \0 of the string */ + if (strlen(json) + 1 >= NETWORK_GAMESCRIPT_JSON_LENGTH) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_GAMESCRIPT); @@ -567,6 +592,17 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const char *js return NETWORK_RECV_STATUS_OKAY; } +/** Send ping-reply (pong) to admin **/ +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32 d1) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_PONG); + + p->Send_uint32(d1); + this->SendPacket(p); + + return NETWORK_RECV_STATUS_OKAY; +} + /** Send the names of the commands. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames() { diff --git a/src/network/network_admin.h b/src/network/network_admin.h index c8241cabf5..cb478fc7e7 100644 --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -35,8 +35,10 @@ protected: virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p); + virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p); NetworkRecvStatus SendProtocol(); + NetworkRecvStatus SendPong(uint32 d1); public: AdminUpdateFrequency update_frequency[ADMIN_UPDATE_END]; ///< Admin requested update intervals. uint32 realtime_connect; ///< Time of connection. @@ -69,6 +71,7 @@ public: NetworkRecvStatus SendGameScript(const char *json); NetworkRecvStatus SendCmdNames(); NetworkRecvStatus SendCmdLogging(ClientID client_id, const CommandPacket *cp); + NetworkRecvStatus SendRconEnd(const char *command); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 07bf8ab9fb..e6e91897c3 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -778,8 +778,10 @@ void ClientNetworkContentSocketHandler::SendReceive() } if (this->CanSendReceive()) { - this->ReceivePackets(); - this->lastActivity = _realtime_tick; + if (this->ReceivePackets()) { + /* Only update activity once a packet is received, instead of everytime we try it. */ + this->lastActivity = _realtime_tick; + } } this->SendPackets(); diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 7260febdf1..a46f5f3923 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -84,6 +84,15 @@ void ScriptConfig::ClearConfigList() this->settings.clear(); } +void ScriptConfig::AnchorUnchangeableSettings() +{ + for (ScriptConfigItemList::const_iterator it = this->GetConfigList()->begin(); it != this->GetConfigList()->end(); it++) { + if (((*it).flags & SCRIPTCONFIG_INGAME) == 0) { + this->SetSetting((*it).name, this->GetSetting((*it).name)); + } + } +} + int ScriptConfig::GetSetting(const char *name) const { SettingValueList::const_iterator it = this->settings.find(name); diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 23822de88e..0350f8ded9 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -107,6 +107,16 @@ public: SSS_FORCE_GAME, ///< Get the Script config from the current game }; + /** + * As long as the default of a setting has not been changed, the value of + * the setting is not stored. This to allow changing the difficulty setting + * without having to reset the script's config. However, when a setting may + * not be changed in game, we must "anchor" this value to what the setting + * would be at the time of starting. Otherwise changing the difficulty + * setting would change the setting's value (which isn't allowed). + */ + void AnchorUnchangeableSettings(); + /** * Get the value of a setting for this config. It might fallback to his * 'info' to find the default value (if not set or if not-custom difficulty