summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Pérez-Cerezo <gabriel@gpcf.eu>2019-11-28 12:30:21 +0100
committerGabriel Pérez-Cerezo <gabriel@gpcf.eu>2019-11-28 12:30:21 +0100
commitddab98412f3fc47eedfa74f8a4edafd324e59707 (patch)
tree7087657e4b9d90e2e0559bfdc25cf2b3b52e51fe
parent6dc7177a5de51f1329c1be04e7f07be64d5cc76c (diff)
downloadminetest-lifo-fixes.tar.gz
minetest-lifo-fixes.tar.bz2
minetest-lifo-fixes.zip
Add static_save and prevent UDP connect exhaustionslifo-fixes
This merges two pull requests from 5.0
-rw-r--r--CMakeLists.txt4
-rw-r--r--doc/lua_api.txt4
-rw-r--r--src/content_sao.h2
-rw-r--r--src/network/connection.cpp27
-rw-r--r--src/network/connection.h5
-rw-r--r--src/network/networkpacket.cpp9
-rw-r--r--src/network/networkpacket.h2
-rw-r--r--src/object_properties.cpp1
-rw-r--r--src/object_properties.h1
-rw-r--r--src/script/common/c_content.cpp5
-rw-r--r--src/server.cpp78
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 = <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<ConnectionCommand> 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="<<PP2(spritediv);
+ os << ", static_save=" << static_save;
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
os<<", is_visible="<<is_visible;
os<<", makes_footstep_sound="<<makes_footstep_sound;
diff --git a/src/object_properties.h b/src/object_properties.h
index 908757a64..9bfe7ea7b 100644
--- a/src/object_properties.h
+++ b/src/object_properties.h
@@ -54,6 +54,7 @@ struct ObjectProperties
std::string infotext;
//! For dropped items, this contains item information.
std::string wield_item;
+ bool static_save = true;
ObjectProperties();
std::string dump();
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index c0e29abf0..24b84e0d0 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -273,7 +273,10 @@ void read_object_properties(lua_State *L, int index,
prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
}
lua_pop(L, 1);
+
getstringfield(L, -1, "infotext", prop->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"<<std::endl;
} catch (ClientNotFoundException &e) {
@@ -1052,30 +1060,45 @@ void Server::Receive()
DSTACK(FUNCTION_NAME);
SharedBuffer<u8> 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()="
- <<e.what()<<std::endl;
- }
- catch(SerializationError &e) {
- infostream<<"Server::Receive(): "
- "SerializationError: what()="
- <<e.what()<<std::endl;
- }
- catch(ClientStateError &e) {
- errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
- DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
- L"Try reconnecting or updating your client");
- }
- catch(con::PeerNotFoundException &e) {
- // Do nothing
- }
+ bool first = true;
+ NetworkPacket pkt;
+ for (;;) {
+ pkt.clear();
+ peer_id = 0;
+ try {
+ /*
+ In the first iteration *wait* for a packet, afterwards process
+ all packets that are immediately available (no waiting).
+ */
+ if (first) {
+ m_con.Receive(&pkt);
+ first = false;
+ } else {
+ if (!m_con.TryReceive(&pkt))
+ return;
+ }
+
+ peer_id = pkt.getPeerId();
+ ProcessData(&pkt);
+
+ } catch (const con::InvalidIncomingDataException &e) {
+ infostream << "Server::Receive(): InvalidIncomingDataException: what()="
+ << e.what() << std::endl;
+ } catch (const SerializationError &e) {
+ infostream << "Server::Receive(): SerializationError: what()="
+ << e.what() << std::endl;
+ } catch (const ClientStateError &e) {
+ errorstream << "ProcessData: peer=" << peer_id << " what()="
+ << e.what() << std::endl;
+ DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
+ L"Try reconnecting or updating your client");
+ } catch (const con::PeerNotFoundException &e) {
+ // Do nothing
+ } catch (const con::NoIncomingDataException &e) {
+ return;
+ }
+ }
+
}
PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
@@ -3682,6 +3705,11 @@ void dedicated_server_loop(Server &server, bool &kill)
static const float profiler_print_interval =
g_settings->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