From ddab98412f3fc47eedfa74f8a4edafd324e59707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20P=C3=A9rez-Cerezo?= Date: Thu, 28 Nov 2019 12:30:21 +0100 Subject: Add static_save and prevent UDP connect exhaustions This merges two pull requests from 5.0 --- CMakeLists.txt | 4 +-- doc/lua_api.txt | 4 +++ src/content_sao.h | 2 ++ src/network/connection.cpp | 27 +++++++++++--- src/network/connection.h | 5 ++- src/network/networkpacket.cpp | 9 +++++ src/network/networkpacket.h | 2 +- src/object_properties.cpp | 1 + src/object_properties.h | 1 + src/script/common/c_content.cpp | 5 +++ src/server.cpp | 78 ++++++++++++++++++++++++++++------------- 11 files changed, 104 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95f1f28d3..b63b10f70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ set(PROJECT_NAME_CAPITALIZED "Minetest") set(VERSION_MAJOR 0) set(VERSION_MINOR 4) set(VERSION_PATCH 17) -set(VERSION_TWEAK 1) -set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string") +set(VERSION_TWEAK 2) +set(VERSION_EXTRA "LinuxForks" CACHE STRING "Stuff to append to version string") # Change to false for releases set(DEVELOPMENT_BUILD FALSE) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 728fd0a1c..ca6f1585f 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4048,6 +4048,10 @@ Definition tables nametag = "", -- by default empty, for players their name is shown if empty nametag_color = , -- sets color of nametag as ColorSpec infotext = "", -- by default empty, text to be shown when pointed at object + static_save = true, + -- ^ If false, never save this object statically. It will simply be deleted when the block gets unloaded. + -- ^ The get_staticdata() callback is never called then. + -- ^ Defaults to 'true' } ### Entity definition (`register_entity`) diff --git a/src/content_sao.h b/src/content_sao.h index 0dad54805..9444ee758 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -102,6 +102,8 @@ public: const std::string &data); void step(float dtime, bool send_recommended); std::string getClientInitializationData(u16 protocol_version); + bool isStaticAllowed() const + { return m_prop.static_save; } void getStaticData(std::string *result) const; int punch(v3f dir, const ToolCapabilities *toolcap=NULL, diff --git a/src/network/connection.cpp b/src/network/connection.cpp index fb3ba92ae..a504bbc08 100644 --- a/src/network/connection.cpp +++ b/src/network/connection.cpp @@ -2884,16 +2884,21 @@ void Connection::Disconnect() putCommand(c); } -void Connection::Receive(NetworkPacket* pkt) +bool Connection::Receive(NetworkPacket *pkt, u32 timeout) { + /* + Note that this function can potentially wait infinitely if non-data + events keep happening before the timeout expires. + This is not considered to be a problem (is it?) + */ for(;;) { - ConnectionEvent e = waitEvent(m_bc_receive_timeout); + ConnectionEvent e = waitEvent(timeout); if (e.type != CONNEVENT_NONE) LOG(dout_con << getDesc() << ": Receive: got event: " << e.describe() << std::endl); switch(e.type) { case CONNEVENT_NONE: - throw NoIncomingDataException("No incoming data"); + return false; case CONNEVENT_DATA_RECEIVED: // Data size is lesser than command size, ignoring packet if (e.data.getSize() < 2) { @@ -2901,7 +2906,7 @@ void Connection::Receive(NetworkPacket* pkt) } pkt->putRawPacket(*e.data, e.data.getSize(), e.peer_id); - return; + return true; case CONNEVENT_PEER_ADDED: { UDPPeer tmp(e.peer_id, e.address, this); if (m_bc_peerhandler) @@ -2919,7 +2924,19 @@ void Connection::Receive(NetworkPacket* pkt) "(port already in use?)"); } } - throw NoIncomingDataException("No incoming data"); + return false; +} + +void Connection::Receive(NetworkPacket *pkt) +{ + bool any = Receive(pkt, m_bc_receive_timeout); + if (!any) + throw NoIncomingDataException("No incoming data"); +} + +bool Connection::TryReceive(NetworkPacket *pkt) +{ + return Receive(pkt, 0); } void Connection::Send(u16 peer_id, u8 channelnum, diff --git a/src/network/connection.h b/src/network/connection.h index 8b7ed9773..a202fa2f5 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -1016,6 +1016,7 @@ public: bool Connected(); void Disconnect(); void Receive(NetworkPacket* pkt); + bool TryReceive(NetworkPacket* pkt); void Send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable); u16 GetPeerID() { return m_peer_id; } Address GetPeerAddress(u16 peer_id); @@ -1050,6 +1051,8 @@ protected: UDPSocket m_udpSocket; MutexedQueue m_command_queue; + bool Receive(NetworkPacket *pkt, u32 timeout); + void putEvent(ConnectionEvent &e); void TriggerSend() @@ -1074,7 +1077,7 @@ private: // Backwards compatibility PeerHandler *m_bc_peerhandler; int m_bc_receive_timeout; - + bool m_shutting_down; u16 m_next_remote_peer_id; diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp index c4fcf9600..7c2c7d0f9 100644 --- a/src/network/networkpacket.cpp +++ b/src/network/networkpacket.cpp @@ -65,6 +65,15 @@ void NetworkPacket::putRawPacket(u8 *data, u32 datasize, u16 peer_id) memcpy(m_data.data(), &data[2], m_datasize); } +void NetworkPacket::clear() +{ + m_data.clear(); + m_datasize = 0; + m_read_offset = 0; + m_command = 0; + m_peer_id = 0; +} + const char* NetworkPacket::getString(u32 from_offset) { checkReadOffset(from_offset, 0); diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h index 83dc33f6f..fc14d61d8 100644 --- a/src/network/networkpacket.h +++ b/src/network/networkpacket.h @@ -35,7 +35,7 @@ public: ~NetworkPacket(); void putRawPacket(u8 *data, u32 datasize, u16 peer_id); - + void clear(); // Getters u32 getSize() { return m_datasize; } u16 getPeerId() { return m_peer_id; } diff --git a/src/object_properties.cpp b/src/object_properties.cpp index a77368151..543c0e876 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -72,6 +72,7 @@ std::string ObjectProperties::dump() } os<<"]"; os<<", spritediv="<infotext); + getboolfield(L, -1, "static_save", prop->static_save); + lua_getfield(L, -1, "wield_item"); if (!lua_isnil(L, -1)) prop->wield_item = read_item(L, -1, idef).getItemString(); @@ -346,6 +349,8 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec"); lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size()); lua_setfield(L, -2, "infotext"); + lua_pushboolean(L, prop->static_save); + lua_setfield(L, -2, "static_save"); lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size()); lua_setfield(L, -2, "wield_item"); } diff --git a/src/server.cpp b/src/server.cpp index 71a349b08..4b54c2398 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -90,6 +90,15 @@ void *ServerThread::run() DSTACK(FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER + /* + * The real business of the server happens on the ServerThread. + * How this works: + * AsyncRunStep() runs an actual server step as soon as enough time has + * passed (dedicated_server_loop keeps track of that). + * Receive() blocks at least(!) 30ms waiting for a packet (so this loop + * doesn't busy wait) and will process any remaining packets. + */ + m_server->AsyncRunStep(true); while (!stopRequested()) { @@ -100,7 +109,6 @@ void *ServerThread::run() m_server->Receive(); - } catch (con::NoIncomingDataException &e) { } catch (con::PeerNotFoundException &e) { infostream<<"Server: PeerNotFoundException"< data; u16 peer_id; - try { - NetworkPacket pkt; - m_con.Receive(&pkt); - peer_id = pkt.getPeerId(); - ProcessData(&pkt); - } - catch(con::InvalidIncomingDataException &e) { - infostream<<"Server::Receive(): " - "InvalidIncomingDataException: what()=" - <getFloat("profiler_print_interval"); + /* + * The dedicated server loop only does time-keeping (in Server::step) and + * provides a way to main.cpp to kill the server externally (bool &kill). + */ + for(;;) { // This is kind of a hack but can be done like this // because server.step() is very light -- cgit v1.2.3