From f03922f2188a72d746a91048725679ffb34afe42 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Fri, 21 Jun 2024 16:33:44 -0500 Subject: [PATCH 01/24] Basic Lan Implmentation --- builtin/mainmenu/serverlistmgr.lua | 8 + builtin/mainmenu/tab_online.lua | 21 +- builtin/settingtypes.txt | 3 + src/CMakeLists.txt | 1 + src/client/clientlauncher.cpp | 2 + src/debug.h | 2 +- src/defaultsettings.cpp | 1 + src/fm_porting.h | 96 ++++++++++ src/log_types.cpp | 101 ++++++++++ src/log_types.h | 55 ++++++ src/network/CMakeLists.txt | 1 + src/network/address.h | 4 + src/network/lan.cpp | 296 +++++++++++++++++++++++++++++ src/network/lan.h | 46 +++++ src/script/lua_api/l_mainmenu.cpp | 48 +++++ src/script/lua_api/l_mainmenu.h | 11 ++ src/server.cpp | 9 + src/server.h | 4 + src/server/serverlist.cpp | 36 ++++ src/server/serverlist.h | 10 + src/threading/CMakeLists.txt | 2 + src/threading/concurrent_map.h | 209 ++++++++++++++++++++ src/threading/lock.cpp | 131 +++++++++++++ src/threading/lock.h | 164 ++++++++++++++++ src/threading/thread_vector.cpp | 118 ++++++++++++ src/threading/thread_vector.h | 37 ++++ 26 files changed, 1414 insertions(+), 2 deletions(-) create mode 100644 src/fm_porting.h create mode 100644 src/log_types.cpp create mode 100644 src/log_types.h create mode 100644 src/network/lan.cpp create mode 100644 src/network/lan.h create mode 100644 src/threading/concurrent_map.h create mode 100644 src/threading/lock.cpp create mode 100644 src/threading/lock.h create mode 100644 src/threading/thread_vector.cpp create mode 100644 src/threading/thread_vector.h diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua index 601b42110..8fc09d85f 100644 --- a/builtin/mainmenu/serverlistmgr.lua +++ b/builtin/mainmenu/serverlistmgr.lua @@ -153,6 +153,14 @@ local function fetch_geoip() end function serverlistmgr.sync() + if minetest.settings:get("serverlist_lan") then + if core.ask_lan_servers then --This checks if the function exists before running it. + core.ask_lan_servers(); + else + print("core.ask_lan_servers isn't defined.") + end + end + if not serverlistmgr.servers then serverlistmgr.servers = {{ name = fgettext("Loading..."), diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index d93f45dcf..e1653dce1 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -22,6 +22,24 @@ local function get_sorted_servers() incompatible = {} } + --Special thanks to proller for letting use use the get_lan_servers function. + if minetest.settings:get_bool("serverlist_lan") then + if core.get_lan_servers then + servers.lan = core.get_lan_servers(); + + for _, server in ipairs(servers.lan) do + server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max) + end + else + print("core.get_lan_servers isn't defined.") + servers.lan = {} + end + else + servers.lan = {} + end + + print(dump(servers.lan)) + local favs = serverlistmgr.get_favorites() local taken_favs = {} local result = menudata.search_result or serverlistmgr.servers @@ -154,11 +172,12 @@ local function get_formspec(tabview, name, tabdata) local servers = get_sorted_servers() local dividers = { + lan = "1,#00ff00," .. fgettext("Lan") .. ",,,0,0,,", fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,", public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,", incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,," } - local order = {"fav", "public", "incompatible"} + local order = {"lan", "fav", "public", "incompatible"} tabdata.lookup = {} -- maps row number to server local rows = {} diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index aca960590..c38322306 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -819,6 +819,9 @@ server_url (Server URL) string https://minetest.net # Automatically report to the serverlist. server_announce (Announce server) bool false +# Make local servers visible to local clients. +serverlist_lan (Show local servers) bool true + # Announce to this serverlist. serverlist_url (Serverlist URL) string servers.minetest.net diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 955bf05f2..00d5d0ca5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -417,6 +417,7 @@ set(common_SRCS light.cpp lighting.cpp log.cpp + #log_types.cpp main.cpp map.cpp map_settings_manager.cpp diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 6379fc141..b4af58eee 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "server/serverlist.h" #if USE_SOUND #include "sound/sound_openal.h" @@ -536,6 +537,7 @@ bool ClientLauncher::launch_game(std::string &error_message, void ClientLauncher::main_menu(MainMenuData *menudata) { + ServerList::lan_get(); bool *kill = porting::signal_handler_killstatus(); video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); diff --git a/src/debug.h b/src/debug.h index 80497f2b3..3a16c9dde 100644 --- a/src/debug.h +++ b/src/debug.h @@ -78,7 +78,7 @@ void debug_set_exception_handler(); These should be put into every thread */ -#if CATCH_UNHANDLED_EXCEPTIONS == 1 +#if CATCH_UNHANDLED_EXCEPTIONS == 0 #define BEGIN_DEBUG_EXCEPTION_HANDLER try { #define END_DEBUG_EXCEPTION_HANDLER \ } catch (std::exception &e) { \ diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index f16c56db4..09a55e220 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -529,6 +529,7 @@ void set_default_settings() Mapgen::setDefaultSettings(settings); // Server list announcing + settings->setDefault("serverlist_lan", "true"); settings->setDefault("server_announce", "false"); settings->setDefault("server_url", ""); settings->setDefault("server_address", ""); diff --git a/src/fm_porting.h b/src/fm_porting.h new file mode 100644 index 000000000..43ca4340f --- /dev/null +++ b/src/fm_porting.h @@ -0,0 +1,96 @@ +#pragma once + +#include "porting.h" + +#if defined(linux) || defined(__linux) + #include +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + #include + #include +#elif defined(__NetBSD__) + #include +#elif defined(__APPLE__) + #include +#endif + +#if defined(linux) || defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define PORTING_USE_PTHREAD 1 + #include +#endif + +namespace porting +{ + +extern std::atomic_bool g_sighup, g_siginfo; + + +#if defined(linux) || defined(__linux) + inline void setThreadName(const char *name) { + /* It would be cleaner to do this with pthread_setname_np, + * which was added to glibc in version 2.12, but some major + * distributions are still runing 2.11 and previous versions. + */ + prctl(PR_SET_NAME, name); + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + inline void setThreadName(const char *name) { + pthread_set_name_np(pthread_self(), name); + } +#elif defined(__NetBSD__) + inline void setThreadName(const char *name) { + pthread_setname_np(pthread_self(), name); + } +#elif defined(_MSC_VER) + typedef struct tagTHREADNAME_INFO { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero + } THREADNAME_INFO; + + inline void setThreadName(const char *name) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = -1; + info.dwFlags = 0; + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *) &info); + } __except (EXCEPTION_CONTINUE_EXECUTION) {} + } +#elif defined(__APPLE__) + inline void setThreadName(const char *name) { + pthread_setname_np(name); + } +#elif defined(_WIN32) || defined(__GNU__) + inline void setThreadName(const char* name) {} +#else +#ifndef __EMSCRIPTEN__ + #warning "Unrecognized platform, thread names will not be available." +#endif + + inline void setThreadName(const char* name) {} +#endif + + inline void setThreadPriority(int priority) { +#if PORTING_USE_PTHREAD + // http://en.cppreference.com/w/cpp/thread/thread/native_handle + sched_param sch; + //int policy; + //pthread_getschedparam(pthread_self(), &policy, &sch); + sch.sched_priority = priority; + if(pthread_setschedparam(pthread_self(), SCHED_FIFO /*SCHED_RR*/, &sch)) { + //std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n'; + } +#endif + } + + +#ifndef SERVER + +//void irr_device_wait_egl (irr::IrrlichtDevice * device = nullptr); + +#endif + + +} \ No newline at end of file diff --git a/src/log_types.cpp b/src/log_types.cpp new file mode 100644 index 000000000..6d623234f --- /dev/null +++ b/src/log_types.cpp @@ -0,0 +1,101 @@ +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#include "log_types.h" +#include "convert_json.h" +#include "irr_v3d.h" +#include "network/address.h" + +std::ostream &operator<<(std::ostream &s, const v2s16 &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} + +std::ostream &operator<<(std::ostream &s, const v2s32 &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} + +std::ostream &operator<<(std::ostream &s, const v2f &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} + +std::ostream &operator<<(std::ostream &s, const v3pos_t &p) +{ + s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; + return s; +} + +std::ostream &operator<<(std::ostream &s, const v3f &p) +{ + s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; + return s; +} + +#if USE_OPOS64 +std::ostream &operator<<(std::ostream &s, const v3opos_t &p) +{ + s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; + return s; +} +#endif + +std::ostream &operator<<(std::ostream &s, const std::map &p) +{ + for (auto &i : p) + s << i.first << "=" << i.second << " "; + return s; +} + +std::ostream &operator<<(std::ostream &s, const irr::video::SColor &c) +{ + s << "c32(" << c.color << ": a=" << c.getAlpha() << ",r=" << c.getRed() + << ",g=" << c.getGreen() << ",b=" << c.getBlue() << ")"; + return s; +} + +std::ostream &operator<<(std::ostream &s, const irr::video::SColorf &c) +{ + s << "cf32(" + << "a=" << c.getAlpha() << ",r=" << c.getRed() << ",g=" << c.getGreen() + << ",b=" << c.getBlue() << ")"; + return s; +} + +#include "util/string.h" +std::ostream &operator<<(std::ostream &s, const std::wstring &w) +{ + s << wide_to_utf8(w); + return s; +} + +std::ostream &operator<<(std::ostream &s, const Json::Value &json) +{ + s << fastWriteJson(json); + return s; +} + +std::ostream &operator<<(std::ostream &s, const Address &addr) +{ + addr.print(s); + // s << addr.getPort(); + return s; +} \ No newline at end of file diff --git a/src/log_types.h b/src/log_types.h new file mode 100644 index 000000000..7a24f2c90 --- /dev/null +++ b/src/log_types.h @@ -0,0 +1,55 @@ +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#ifndef LOG_TYPES_HEADER +#define LOG_TYPES_HEADER + +//#include "log.h" //for replacing log.h to log_types.h in includes + +#include "irr_v2d.h" +#include "irr_v3d.h" + +#include +std::ostream &operator<<(std::ostream &s, const v2s16 &p); +std::ostream &operator<<(std::ostream &s, const v2s32 &p); +std::ostream &operator<<(std::ostream &s, const v2f &p); +std::ostream &operator<<(std::ostream &s, const v3pos_t &p); +std::ostream &operator<<(std::ostream &s, const v3f &p); +#if USE_OPOS64 +std::ostream &operator<<(std::ostream &s, const v3opos_t &p); +#endif + +#include +std::ostream &operator<<(std::ostream &s, const irr::video::SColor &c); +std::ostream &operator<<(std::ostream &s, const irr::video::SColorf &c); + +#include +std::ostream &operator<<(std::ostream &s, const std::map &p); + +std::ostream &operator<<(std::ostream &s, const std::wstring &w); + +namespace Json +{ +class Value; +}; + +//std::ostream &operator<<(std::ostream &s, const Json::Value &json); + +class Address; +std::ostream &operator<<(std::ostream &s, const Address &addr); + +#endif \ No newline at end of file diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index d2e2f52e9..1a37eb995 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -2,6 +2,7 @@ set(common_network_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/address.cpp ${CMAKE_CURRENT_SOURCE_DIR}/connection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/connectionthreads.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/networkpacket.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serverpackethandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serveropcodes.cpp diff --git a/src/network/address.h b/src/network/address.h index 2fbf419a7..6eecc3f79 100644 --- a/src/network/address.h +++ b/src/network/address.h @@ -46,6 +46,9 @@ public: Address(u32 address, u16 port); Address(u8 a, u8 b, u8 c, u8 d, u16 port); Address(const IPv6AddressBytes *ipv6_bytes, u16 port); + Address(const in6_addr & addr, u16 port) { setAddress(addr); setPort(port); }; + Address(const sockaddr_in6 & sai) { m_address.ipv6 = sai.sin6_addr; m_addr_family = sai.sin6_family; m_port = ntohs(sai.sin6_port); }; + Address(const sockaddr_in & sai) { m_address.ipv4 = sai.sin_addr; m_addr_family = sai.sin_family; m_port = ntohs(sai.sin_port); }; bool operator==(const Address &address) const; bool operator!=(const Address &address) const { return !(*this == address); } @@ -74,6 +77,7 @@ public: void setAddress(u32 address); void setAddress(u8 a, u8 b, u8 c, u8 d); void setAddress(const IPv6AddressBytes *ipv6_bytes); + void setAddress(const in6_addr & addr) { m_address.ipv6 = addr; m_addr_family = AF_INET6;} void setPort(u16 port); private: diff --git a/src/network/lan.cpp b/src/network/lan.cpp new file mode 100644 index 000000000..e7f163395 --- /dev/null +++ b/src/network/lan.cpp @@ -0,0 +1,296 @@ +/* +Copyright (C) 2016 proller +*/ + +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#include "network/lan.h" +#include +#include "convert_json.h" +#include "socket.h" +#include "log.h" +#include "settings.h" +#include "version.h" +#include "networkprotocol.h" +#include "server/serverlist.h" +#include "debug.h" +#include "json/json.h" +#include "porting.h" +#include "threading/thread_vector.h" +#include "threading/concurrent_map.h" +#include "network/address.h" + +//copypaste from ../socket.cpp +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +// Without this some of the network functions are not found on mingw +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#include +#define LAST_SOCKET_ERR() WSAGetLastError() +typedef SOCKET socket_t; +typedef int socklen_t; +#else +#include +#include +#include +#include +#include +#include +#include + +#ifndef __ANDROID__ +#include +#define HAVE_IFADDRS 1 +#endif + +#define LAST_SOCKET_ERR() (errno) +typedef int socket_t; +#endif + +const static unsigned short int adv_port = 29998; +static std::string ask_str; + +lan_adv::lan_adv() : thread_vector("lan_adv") +{ +} + +void lan_adv::ask() +{ + reanimate(); + + if (ask_str.empty()) { + Json::Value j; + j["cmd"] = "ask"; + ask_str = fastWriteJson(j); + } + + send_string(ask_str); +} + +void lan_adv::send_string(const std::string &str) +{ + try { + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(adv_port); + addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + UDPSocket socket_send(false); + int set_option_on = 1; + setsockopt(socket_send.GetHandle(), SOL_SOCKET, SO_BROADCAST, + (const char *)&set_option_on, sizeof(set_option_on)); + socket_send.Send(Address(addr), str.c_str(), str.size()); + } catch (const std::exception &e) { + verbosestream << "udp broadcast send4 fail " << e.what() << "\n"; + } + + std::vector scopes; +// todo: windows and android + +#if HAVE_IFADDRS + struct ifaddrs *ifaddr = nullptr, *ifa = nullptr; + if (getifaddrs(&ifaddr) < 0) { + } else { + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + auto sa = *((struct sockaddr_in6 *)ifa->ifa_addr); + if (sa.sin6_scope_id) + scopes.push_back(sa.sin6_scope_id); + + /*errorstream<<"in=" << ifa->ifa_name << " a="<ifa_addr)).serializeString()<<" ba=" << ifa->ifa_broadaddr <<" sc=" << sa.sin6_scope_id <<" fl=" << ifa->ifa_flags + //<< " bn=" << Address(*((struct sockaddr_in6*)ifa->ifa_broadaddr)).serializeString() + <<"\n"; */ + } + } + freeifaddrs(ifaddr); +#endif + + if (scopes.empty()) + scopes.push_back(0); + + struct addrinfo hints + { + }; + + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + struct addrinfo *result = nullptr; + if (!getaddrinfo("ff02::1", nullptr, &hints, &result)) { + for (auto info = result; info; info = info->ai_next) { + try { + sockaddr_in6 addr = *((struct sockaddr_in6 *)info->ai_addr); + addr.sin6_port = htons(adv_port); + UDPSocket socket_send(true); + int set_option_on = 1; + setsockopt(socket_send.GetHandle(), SOL_SOCKET, SO_BROADCAST, + (const char *)&set_option_on, sizeof(set_option_on)); + auto use_scopes = scopes; + if (addr.sin6_scope_id) { + use_scopes.clear(); + use_scopes.push_back(addr.sin6_scope_id); + } + for (auto &scope : use_scopes) { + addr.sin6_scope_id = scope; + socket_send.Send(Address(addr), str.c_str(), str.size()); + } + } catch (const std::exception &e) { + verbosestream << "udp broadcast send6 fail " << e.what() << "\n"; + } + } + freeaddrinfo(result); + } +} + +void lan_adv::serve(unsigned short port) +{ + server_port = port; + restart(); +} + +void *lan_adv::run() +{ + BEGIN_DEBUG_EXCEPTION_HANDLER; + + reg("LanAdv" + (server_port ? std::string("Server") : std::string("Client"))); + + UDPSocket socket_recv(true); + int set_option_off = 0, set_option_on = 1; + setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEADDR, + (const char *)&set_option_on, sizeof(set_option_on)); +#ifdef SO_REUSEPORT + setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEPORT, + (const char *)&set_option_on, sizeof(set_option_on)); +#endif + setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_BROADCAST, + (const char *)&set_option_on, sizeof(set_option_on)); + setsockopt(socket_recv.GetHandle(), IPPROTO_IPV6, IPV6_V6ONLY, + (const char *)&set_option_off, sizeof(set_option_off)); + socket_recv.setTimeoutMs(200); + try { + socket_recv.Bind(Address(in6addr_any, adv_port)); + } catch (const std::exception &e) { + warningstream << m_name << ": cant bind ipv6 address [" << e.what() + << "], trying ipv4. " << std::endl; + try { + socket_recv.Bind(Address((u32)INADDR_ANY, adv_port)); + } catch (const std::exception &e) { + warningstream << m_name << ": cant bind ipv4 too [" << e.what() << "]" + << std::endl; + return nullptr; + } + } + std::unordered_map limiter; + const unsigned int packet_maxsize = 16384; + char buffer[packet_maxsize]; + Json::Reader reader; + std::string answer_str; + Json::Value server; + if (server_port) { + server["name"] = g_settings->get("server_name"); + server["description"] = g_settings->get("server_description"); + server["version"] = g_version_string; + bool strict_checking = g_settings->getBool("strict_protocol_version_checking"); + server["proto_min"] = + strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN; + server["proto_max"] = + strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX; + server["url"] = g_settings->get("server_url"); + server["creative"] = g_settings->getBool("creative_mode"); + server["damage"] = g_settings->getBool("enable_damage"); + server["password"] = g_settings->getBool("disallow_empty_password"); + server["pvp"] = g_settings->getBool("enable_pvp"); + server["port"] = server_port; + server["clients"] = clients_num.load(); + server["clients_max"] = g_settings->getU16("max_users"); + + send_string(fastWriteJson(server)); + } + + while (!stopRequested()) { + BEGIN_DEBUG_EXCEPTION_HANDLER; + Address addr; + int rlen = socket_recv.Receive(addr, buffer, packet_maxsize); + if (rlen <= 0) + continue; + Json::Value p; + if (!reader.parse(std::string(buffer, rlen), p)) { + //errorstream << "cant parse "<< s << "\n"; + continue; + } + auto addr_str = addr.serializeString(); + auto now = porting::getTimeMs(); + //errorstream << " a=" << addr.serializeString() << " : " << addr.getPort() << " l=" << rlen << " b=" << p << " ; server=" << server_port << "\n"; + + if (server_port) { + if (p["cmd"] == "ask" && limiter[addr_str] < now) { + (clients_num.load() ? infostream : actionstream) + << "lan: want play " << addr_str << std::endl; + + server["clients"] = clients_num.load(); + answer_str = fastWriteJson(server); + + limiter[addr_str] = now + 3000; + UDPSocket socket_send(true); + addr.setPort(adv_port); + socket_send.Send(addr, answer_str.c_str(), answer_str.size()); + } + } else { + if (p["cmd"] == "ask") { + actionstream << "lan: want play " << addr_str << std::endl; + } + if (p["port"].isInt()) { + p["address"] = addr_str; + auto key = addr_str + ":" + p["port"].asString(); + if (p["cmd"].asString() == "shutdown") { + //infostream << "server shutdown " << key << "\n"; + collected.erase(key); + fresh = true; + } else { + if (!collected.count(key)) + actionstream << "lan server start " << key << "\n"; + collected.insert_or_assign(key, p); + fresh = true; + } + } + + //errorstream<<" current list: ";for (auto & i : collected) {errorstream<< i.first <<" ; ";}errorstream< + +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include "threading/thread_vector.h" +#include "threading/concurrent_map.h" + + +class lan_adv : public thread_vector +{ +public: + void *run(); + + lan_adv(); + void ask(); + void send_string(const std::string &str); + + void serve(unsigned short port); + + concurrent_map collected; + std::atomic_bool fresh; + std::atomic_int clients_num; + +private: + unsigned short server_port = 0; +}; \ No newline at end of file diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index a5913e807..6a637f7d7 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "convert_json.h" #include "content/content.h" #include "content/subgames.h" +#include "server/serverlist.h" #include "mapgen/mapgen.h" #include "settings.h" #include "client/client.h" @@ -40,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content/mod_configuration.h" #include "threading/mutex_auto_lock.h" #include "common/c_converter.h" +#include "json-forwards.h" /******************************************************************************/ std::string ModApiMainMenu::getTextData(lua_State *L, const std::string &name) @@ -1080,6 +1082,48 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L) return 1; } +/******************************************************************************/ + +/* +ModApiMainMenu::l_ask_lan_servers, ModApiMainMenu::l_get_lan_servers +by proller , special thanks for letting us use them. +*/ + +int ModApiMainMenu::l_ask_lan_servers(lua_State *L) +{ + ServerList::lan_get(); + return 0; +} + +int ModApiMainMenu::l_get_lan_servers(lua_State *L) +{ + lua_newtable(L); + int top = lua_gettop(L); + unsigned int index = 1; + + for (const auto &server : ServerList::lan_adv_client.collected) { + lua_pushnumber(L, index); + + lua_newtable(L); + int top_lvl2 = lua_gettop(L); + + for (const auto &field_name : server.second.getMemberNames()) { + lua_pushstring(L, field_name.c_str()); + if (server.second[field_name].isString()) + lua_pushstring(L, server.second[field_name].asCString()); + else if (server.second[field_name].isConvertibleTo(Json::realValue)) + lua_pushnumber(L, server.second[field_name].asDouble()); + else + lua_pushnil(L); + lua_settable(L, top_lvl2); + } + + lua_settable(L, top); + ++index; + } + return 1; +} + /******************************************************************************/ void ModApiMainMenu::Initialize(lua_State *L, int top) { @@ -1132,6 +1176,8 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(open_dir); API_FCT(share_file); API_FCT(do_async_callback); + API_FCT(ask_lan_servers); + API_FCT(get_lan_servers); } /******************************************************************************/ @@ -1160,4 +1206,6 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(get_max_supp_proto); API_FCT(get_language); API_FCT(gettext); + API_FCT(get_lan_servers); + API_FCT(ask_lan_servers); } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 5535d2170..38d7c50cc 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -60,6 +60,17 @@ private: */ static bool mayModifyPath(std::string path); + //lan + + /* + ModApiMainMenu::l_ask_lan_servers, ModApiMainMenu::l_get_lan_servers + by proller , special thanks for letting us use it. + */ + + static int l_ask_lan_servers(lua_State *L); + + static int l_get_lan_servers(lua_State *L); + //api calls static int l_start(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index 316f349b2..5fd50d5aa 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -75,6 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gameparams.h" #include "particles.h" #include "gettext.h" +#include "network/lan.h" class ClientNotFoundException : public BaseException { @@ -561,6 +562,10 @@ void Server::start() // Start thread m_thread->start(); + if (!m_simple_singleplayer_mode && g_settings->getBool("serverlist_lan")) { + lan_adv_server.serve(m_bind_addr.getPort()); + }; + // ASCII art for the win! const char *art[] = { " __. __. __. ", @@ -778,6 +783,10 @@ void Server::AsyncRunStep(float dtime, bool initial_step) } #endif + if (!isSingleplayer() && g_settings->getBool("serverlist_lan")) { + lan_adv_server.clients_num = m_clients.getPlayerNames().size(); + }; + /* Check added and deleted active objects */ diff --git a/src/server.h b/src/server.h index 16c1ea4cc..3f4824830 100644 --- a/src/server.h +++ b/src/server.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include "network/lan.h" #include "irr_v3d.h" #include "map.h" #include "hud.h" @@ -671,6 +672,9 @@ private: // The server mainly operates in this thread ServerThread *m_thread = nullptr; + // For local server discovery. + lan_adv lan_adv_server; + /* Client interface */ diff --git a/src/server/serverlist.cpp b/src/server/serverlist.cpp index e702ba73d..1165ae9da 100644 --- a/src/server/serverlist.cpp +++ b/src/server/serverlist.cpp @@ -28,9 +28,45 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "convert_json.h" #include "httpfetch.h" #include "server.h" +#include "network/lan.h" +#include "json/json.h" namespace ServerList { + +/* +Special thanks to proller for +letting us use the methods lan_get() and lan_fresh() +as well as the lan_adv class. +*/ + +static std::string ask_str; + +lan_adv lan_adv_client; + +void lan_get() { + if (!g_settings->getBool("serverlist_lan")) + return; + lan_adv_client.ask(); +} + +/* + if (ask_str.empty()) { + Json::Value j; + j["cmd"] = "ask"; + j["proto_min"] = Server::getProtocolVersionMin(); + j["proto_max"] = Server::getProtocolVersionMax(); + ask_str = fastWriteJson(j); + + }; + lan_adv_client.send_string(ask_str); +*/ + +bool lan_fresh() { + auto result = lan_adv_client.fresh.load(); + lan_adv_client.fresh = false; + return result; +} #if USE_CURL void sendAnnounce(AnnounceAction action, const u16 port, diff --git a/src/server/serverlist.h b/src/server/serverlist.h index 2e2b8590f..568337278 100644 --- a/src/server/serverlist.h +++ b/src/server/serverlist.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content/mods.h" #include "json-forwards.h" #include +#include "network/lan.h" #pragma once @@ -28,6 +29,15 @@ with this program; if not, write to the Free Software Foundation, Inc., namespace ServerList { + /* + Special thanks to proller for + letting us use the methods lan_get() and lan_fresh() + as well as the lan_adv class. + */ + extern lan_adv lan_adv_client; + void lan_get(); + bool lan_fresh(); + #if USE_CURL enum AnnounceAction {AA_START, AA_UPDATE, AA_DELETE}; void sendAnnounce(AnnounceAction, u16 port, diff --git a/src/threading/CMakeLists.txt b/src/threading/CMakeLists.txt index 8f86158be..25c7e955c 100644 --- a/src/threading/CMakeLists.txt +++ b/src/threading/CMakeLists.txt @@ -2,5 +2,7 @@ set(JTHREAD_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/event.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lock.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/thread_vector.cpp PARENT_SCOPE) diff --git a/src/threading/concurrent_map.h b/src/threading/concurrent_map.h new file mode 100644 index 000000000..c07971d59 --- /dev/null +++ b/src/threading/concurrent_map.h @@ -0,0 +1,209 @@ +/* +Copyright (C) 2024 proller +*/ + +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#pragma once + +#include + +#include "lock.h" + +template , + class Allocator = std::allocator>> +class concurrent_map_ : public std::map, public LOCKER +{ +public: + typedef typename std::map full_type; + typedef Key key_type; + typedef T mapped_type; + + mapped_type &operator[](const key_type &k) = delete; + mapped_type &operator[](key_type &&k) = delete; + + mapped_type nothing = {}; + + template + mapped_type& get(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + + //if (!full_type::contains(std::forward(args)...)) + if (full_type::find(std::forward(args)...) == full_type::end()) + return nothing; + + return full_type::operator[](std::forward(args)...); + } + + template + decltype(auto) at(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::at(std::forward(args)...); + } + + template + decltype(auto) assign(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::assign(std::forward(args)...); + } + + template + decltype(auto) insert(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::insert(std::forward(args)...); + } + + template + decltype(auto) emplace(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::emplace(std::forward(args)...); + } + + template + decltype(auto) emplace_try(Args &&...args) + { + auto lock = LOCKER::try_lock_unique_rec(); + if (!lock->owns_lock()) + return false; + return full_type::emplace(std::forward(args)...).second; + } + + template + decltype(auto) insert_or_assign(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::insert_or_assign(std::forward(args)...); + } + + template + decltype(auto) empty(Args &&...args) const noexcept + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::empty(std::forward(args)...); + } + + template + decltype(auto) size(Args &&...args) const + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::size(std::forward(args)...); + } + + template + decltype(auto) count(Args &&...args) const + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::count(std::forward(args)...); + } + + template + decltype(auto) contains(Args &&...args) const + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::contains(std::forward(args)...); + } + + template + decltype(auto) find(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::find(std::forward(args)...); + } + + template + decltype(auto) begin(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::begin(std::forward(args)...); + } + + template + decltype(auto) rbegin(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::rbegin(std::forward(args)...); + } + + template + decltype(auto) end(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::end(std::forward(args)...); + } + + template + decltype(auto) rend(Args &&...args) + { + auto lock = LOCKER::lock_shared_rec(); + return full_type::rend(std::forward(args)...); + } + + + template + decltype(auto) erase(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::erase(std::forward(args)...); + } + + template + decltype(auto) clear(Args &&...args) + { + auto lock = LOCKER::lock_unique_rec(); + return full_type::clear(std::forward(args)...); + } +}; + +template , + class Allocator = std::allocator>> +using concurrent_map = concurrent_map_, Key, T, Compare, Allocator>; + +template , class Allocator = std::allocator>> +using concurrent_shared_map = concurrent_map_; + +#if ENABLE_THREADS + +template , + class Allocator = std::allocator>> +using maybe_concurrent_map = concurrent_map; + +#else + +template , + class Allocator = std::allocator>> +class not_concurrent_map : public std::map, + public dummy_locker +{ +public: + typedef typename std::map full_type; + typedef Key key_type; + typedef T mapped_type; + + mapped_type &get(const key_type &k) { return full_type::operator[](k); } +}; + +template , + class Allocator = std::allocator>> +using maybe_concurrent_map = not_concurrent_map; + +#endif \ No newline at end of file diff --git a/src/threading/lock.cpp b/src/threading/lock.cpp new file mode 100644 index 000000000..d80055447 --- /dev/null +++ b/src/threading/lock.cpp @@ -0,0 +1,131 @@ +#include "lock.h" +#include "log.h" +#include "profiler.h" + +#if !defined(NDEBUG) && !defined(LOCK_PROFILE) +//#define LOCK_PROFILE 1 +#endif + +#if LOCK_PROFILE +#define SCOPE_PROFILE(a) ScopeProfiler scp___(g_profiler, "Lock: " a); +#else +#define SCOPE_PROFILE(a) +#endif + +template +recursive_lock::recursive_lock(MUTEX & mtx, std::atomic & thread_id_, bool try_lock): + thread_id(thread_id_) { + auto thread_me = std::hash()(std::this_thread::get_id()); + if(thread_me != thread_id) { + if (try_lock) { + SCOPE_PROFILE("try_lock"); + lock = new GUARD(mtx, try_to_lock); + if (lock->owns_lock()) { + thread_id = thread_me; + return; + } else { +#if LOCK_PROFILE + g_profiler->add("Lock: try_lock fail", 1); +#endif + //infostream<<"not locked "<<" thread="<add("Lock: recursive", 1); +#endif + } + lock = nullptr; +} + +template +recursive_lock::~recursive_lock() { + unlock(); +} + +template +bool recursive_lock::owns_lock() { + if (lock) + return lock; + auto thread_me = std::hash()(std::this_thread::get_id()); + return thread_id == thread_me; +} + +template +void recursive_lock::unlock() { + if(lock) { + thread_id = 0; + lock->unlock(); + delete lock; + lock = nullptr; + } +} + + +template +locker::locker() { + thread_id = 0; +} + +template +std::unique_ptr locker::lock_unique() { + return std::make_unique(mtx); +} + +template +std::unique_ptr locker::try_lock_unique() { + SCOPE_PROFILE("locker::try_lock_unique"); + return std::make_unique(mtx, std::try_to_lock); +} + +template +std::unique_ptr locker::lock_shared() const { + SCOPE_PROFILE("locker::lock_shared"); + return std::make_unique(mtx); +} + +template +std::unique_ptr locker::try_lock_shared() { + SCOPE_PROFILE("locker::try_lock_shared"); + return std::make_unique(mtx, std::try_to_lock); +} + +template +std::unique_ptr> locker::lock_unique_rec() const { + SCOPE_PROFILE("locker::lock_unique_rec"); + return std::make_unique(mtx, thread_id); +} + +template +std::unique_ptr> locker::try_lock_unique_rec() { + SCOPE_PROFILE("locker::try_lock_unique_rec"); + return std::make_unique(mtx, thread_id, true); +} + +template +std::unique_ptr> locker::lock_shared_rec() const { + SCOPE_PROFILE("locker::lock_shared_rec"); + return std::make_unique(mtx, thread_id); +} + +template +std::unique_ptr> locker::try_lock_shared_rec() { + SCOPE_PROFILE("locker::try_lock_shared_rec"); + return std::make_unique(mtx, thread_id, true); +} + + +template class recursive_lock>; +template class locker<>; +#if LOCK_TWO +template class recursive_lock; +template class recursive_lock, try_shared_mutex>; + +template class locker, std::shared_lock>; +#endif \ No newline at end of file diff --git a/src/threading/lock.h b/src/threading/lock.h new file mode 100644 index 000000000..a3cd43e29 --- /dev/null +++ b/src/threading/lock.h @@ -0,0 +1,164 @@ +/* +This file is part of Freeminer. + +Freeminer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Freeminer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Freeminer. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include + +#include "../config.h" + +#ifdef _WIN32 + +//#include "../threading/mutex.h" +using use_mutex = std::mutex; +using try_shared_mutex = use_mutex; +using try_shared_lock = std::unique_lock; +using unique_lock = std::unique_lock; +const auto try_to_lock = std::try_to_lock; + +#else + +typedef std::mutex use_mutex; + + +#if USE_BOOST // not finished + +//#include +#include +//#include +typedef boost::shared_mutex try_shared_mutex; +typedef boost::shared_lock try_shared_lock; +typedef boost::unique_lock unique_lock; +const auto try_to_lock = boost::try_to_lock; +#define LOCK_TWO 1 + +#elif HAVE_SHARED_MUTEX +//#elif __cplusplus >= 201305L + +#include +using try_shared_mutex = std::shared_mutex; +using try_shared_lock = std::shared_lock; +using unique_lock = std::unique_lock; +const auto try_to_lock = std::try_to_lock; +#define LOCK_TWO 1 + +#else + +using try_shared_mutex = use_mutex; +using try_shared_lock = std::unique_lock ; +using unique_lock = std::unique_lock ; +const auto try_to_lock = std::try_to_lock; +#endif + +#endif + + +// http://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads +/* uncomment when need +#include +class semaphore { +private: + std::mutex mtx; + std::condition_variable cv; + int count; + +public: + semaphore(int count_ = 0):count(count_){;} + void notify() { + std::unique_lock lck(mtx); + ++count; + cv.notify_one(); + } + void wait() { + std::unique_lock lck(mtx); + while(count == 0){ + cv.wait(lck); + } + count--; + } +}; +*/ + +template +class recursive_lock { +public: + GUARD * lock; + std::atomic & thread_id; + recursive_lock(MUTEX & mtx, std::atomic & thread_id_, bool try_lock = false); + ~recursive_lock(); + bool owns_lock(); + void unlock(); +}; + +template , class shared_lock = std::unique_lock > +class locker { +public: + using lock_rec_shared = recursive_lock; + using lock_rec_unique = recursive_lock; + + mutable mutex mtx; + mutable std::atomic thread_id; + + locker(); + std::unique_ptr lock_unique(); + std::unique_ptr try_lock_unique(); + std::unique_ptr lock_shared() const; + std::unique_ptr try_lock_shared(); + std::unique_ptr lock_unique_rec() const; + std::unique_ptr try_lock_unique_rec(); + std::unique_ptr lock_shared_rec() const; + std::unique_ptr try_lock_shared_rec(); +}; + +using shared_locker = locker; + +class dummy_lock { +public: + ~dummy_lock() {}; //no unused variable warning + bool owns_lock() {return true;} + bool operator!() {return true;} + dummy_lock * operator->() {return this; } + void unlock() {}; +}; + +class dummy_locker { +public: + dummy_lock lock_unique() { return {}; }; + dummy_lock try_lock_unique() { return {}; }; + dummy_lock lock_shared() { return {}; }; + dummy_lock try_lock_shared() { return {}; }; + dummy_lock lock_unique_rec() { return {}; }; + dummy_lock try_lock_unique_rec() { return {}; }; + dummy_lock lock_shared_rec() { return {}; }; + dummy_lock try_lock_shared_rec() { return {}; }; +}; + + +#if ENABLE_THREADS + +using maybe_locker = locker<>; +using maybe_shared_locker = shared_locker; + +#else + +using maybe_locker = dummy_locker; +using maybe_shared_locker = dummy_locker; + +#endif \ No newline at end of file diff --git a/src/threading/thread_vector.cpp b/src/threading/thread_vector.cpp new file mode 100644 index 000000000..5d206f58c --- /dev/null +++ b/src/threading/thread_vector.cpp @@ -0,0 +1,118 @@ +#include "thread_vector.h" +#include "fm_porting.h" +#include "log.h" +#include "porting.h" + +thread_vector::thread_vector(const std::string &name, int priority) : + m_name(name), m_priority(priority) +{ + request_stop = false; +}; + +thread_vector::~thread_vector() +{ + join(); +}; + +void thread_vector::func() +{ + reg(); + run(); +}; + +void thread_vector::reg(const std::string &name, int priority) +{ + if (!name.empty()) + m_name = name; + + porting::setThreadName(m_name.c_str()); + g_logger.registerThread(m_name); + + if (priority) + m_priority = priority; + if (m_priority) + porting::setThreadPriority(m_priority); +}; + +void thread_vector::start(const size_t n) +{ +#if !NDEBUG + infostream << "start thread " << m_name << " n=" << n << std::endl; +#endif + request_stop = false; + for (size_t i = 0; i < n; ++i) { + workers.emplace_back(&thread_vector::func, this); + } +} + +void thread_vector::stop() +{ + request_stop = true; +} + +void thread_vector::join() +{ + stop(); + for (auto &worker : workers) { + try { + if (worker.joinable()) { + worker.join(); + } + } catch (...) { + } + } + workers.clear(); +} + +void thread_vector::restart(size_t n) +{ + join(); + start(n); +} +void thread_vector::reanimate(size_t n) +{ + if (workers.empty()) { + start(n); + } +} + +void thread_vector::sleep(const int seconds) +{ + for (int i = 0; i <= seconds; ++i) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (request_stop) { + return; + } + } +} + +// JThread compat: +bool thread_vector::stopRequested() +{ + return request_stop; +} +bool thread_vector::isRunning() +{ + return !workers.empty(); +} +void thread_vector::wait() +{ + join(); +}; +void thread_vector::kill() +{ + join(); +}; +void *thread_vector::run() +{ + return nullptr; +}; + +bool thread_vector::isCurrentThread() +{ + auto thread_me = std::hash()(std::this_thread::get_id()); + for (auto &worker : workers) + if (thread_me == std::hash()(worker.get_id())) + return true; + return false; +} diff --git a/src/threading/thread_vector.h b/src/threading/thread_vector.h new file mode 100644 index 000000000..8172dd7b6 --- /dev/null +++ b/src/threading/thread_vector.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +class thread_vector { +public: + std::vector workers; + std::atomic_bool request_stop; + + thread_vector(const std::string &name = "Unnamed", int priority = 0); + virtual ~thread_vector(); + + virtual void func(); + + void reg (const std::string &name = "", int priority = 0); + void start (const size_t n = 1); + void restart (const size_t n = 1); + void reanimate (const size_t n = 1); + void stop (); + void join (); + + void sleep(const int second); +// Thread compat: + + bool stopRequested(); + bool isRunning(); + void wait(); + void kill(); + virtual void * run() = 0; + bool isCurrentThread(); +protected: + std::string m_name; + int m_priority = 0; +}; \ No newline at end of file From 9ff9b30e0f7a338f9233cdff6fe26d0b600651d4 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 27 Jun 2024 17:45:13 -0500 Subject: [PATCH 02/24] Remove unneeded freeminer code. --- irr/src/CIrrDeviceSDL.cpp | 2 +- src/fm_porting.h | 96 -------------------------- src/log_types.cpp | 101 --------------------------- src/log_types.h | 55 --------------- src/network/lan.cpp | 11 +-- src/network/lan.h | 4 +- src/server/serverlist.cpp | 12 ---- src/threading/CMakeLists.txt | 1 - src/threading/thread_vector.cpp | 118 -------------------------------- src/threading/thread_vector.h | 37 ---------- 10 files changed, 9 insertions(+), 428 deletions(-) delete mode 100644 src/fm_porting.h delete mode 100644 src/log_types.cpp delete mode 100644 src/log_types.h delete mode 100644 src/threading/thread_vector.cpp delete mode 100644 src/threading/thread_vector.h diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index f8fb66da3..cc7505c72 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -656,7 +656,7 @@ bool CIrrDeviceSDL::run() { os::Timer::tick(); - SEvent irrevent; + SEvent irrevent{}; SDL_Event SDL_event; while (!Close && wrap_PollEvent(&SDL_event)) { diff --git a/src/fm_porting.h b/src/fm_porting.h deleted file mode 100644 index 43ca4340f..000000000 --- a/src/fm_porting.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "porting.h" - -#if defined(linux) || defined(__linux) - #include -#elif defined(__FreeBSD__) || defined(__OpenBSD__) - #include - #include -#elif defined(__NetBSD__) - #include -#elif defined(__APPLE__) - #include -#endif - -#if defined(linux) || defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #define PORTING_USE_PTHREAD 1 - #include -#endif - -namespace porting -{ - -extern std::atomic_bool g_sighup, g_siginfo; - - -#if defined(linux) || defined(__linux) - inline void setThreadName(const char *name) { - /* It would be cleaner to do this with pthread_setname_np, - * which was added to glibc in version 2.12, but some major - * distributions are still runing 2.11 and previous versions. - */ - prctl(PR_SET_NAME, name); - } -#elif defined(__FreeBSD__) || defined(__OpenBSD__) - inline void setThreadName(const char *name) { - pthread_set_name_np(pthread_self(), name); - } -#elif defined(__NetBSD__) - inline void setThreadName(const char *name) { - pthread_setname_np(pthread_self(), name); - } -#elif defined(_MSC_VER) - typedef struct tagTHREADNAME_INFO { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } THREADNAME_INFO; - - inline void setThreadName(const char *name) { - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = -1; - info.dwFlags = 0; - __try { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *) &info); - } __except (EXCEPTION_CONTINUE_EXECUTION) {} - } -#elif defined(__APPLE__) - inline void setThreadName(const char *name) { - pthread_setname_np(name); - } -#elif defined(_WIN32) || defined(__GNU__) - inline void setThreadName(const char* name) {} -#else -#ifndef __EMSCRIPTEN__ - #warning "Unrecognized platform, thread names will not be available." -#endif - - inline void setThreadName(const char* name) {} -#endif - - inline void setThreadPriority(int priority) { -#if PORTING_USE_PTHREAD - // http://en.cppreference.com/w/cpp/thread/thread/native_handle - sched_param sch; - //int policy; - //pthread_getschedparam(pthread_self(), &policy, &sch); - sch.sched_priority = priority; - if(pthread_setschedparam(pthread_self(), SCHED_FIFO /*SCHED_RR*/, &sch)) { - //std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n'; - } -#endif - } - - -#ifndef SERVER - -//void irr_device_wait_egl (irr::IrrlichtDevice * device = nullptr); - -#endif - - -} \ No newline at end of file diff --git a/src/log_types.cpp b/src/log_types.cpp deleted file mode 100644 index 6d623234f..000000000 --- a/src/log_types.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Freeminer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . -*/ - -#include "log_types.h" -#include "convert_json.h" -#include "irr_v3d.h" -#include "network/address.h" - -std::ostream &operator<<(std::ostream &s, const v2s16 &p) -{ - s << "(" << p.X << "," << p.Y << ")"; - return s; -} - -std::ostream &operator<<(std::ostream &s, const v2s32 &p) -{ - s << "(" << p.X << "," << p.Y << ")"; - return s; -} - -std::ostream &operator<<(std::ostream &s, const v2f &p) -{ - s << "(" << p.X << "," << p.Y << ")"; - return s; -} - -std::ostream &operator<<(std::ostream &s, const v3pos_t &p) -{ - s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; - return s; -} - -std::ostream &operator<<(std::ostream &s, const v3f &p) -{ - s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; - return s; -} - -#if USE_OPOS64 -std::ostream &operator<<(std::ostream &s, const v3opos_t &p) -{ - s << "(" << p.X << "," << p.Y << "," << p.Z << ")"; - return s; -} -#endif - -std::ostream &operator<<(std::ostream &s, const std::map &p) -{ - for (auto &i : p) - s << i.first << "=" << i.second << " "; - return s; -} - -std::ostream &operator<<(std::ostream &s, const irr::video::SColor &c) -{ - s << "c32(" << c.color << ": a=" << c.getAlpha() << ",r=" << c.getRed() - << ",g=" << c.getGreen() << ",b=" << c.getBlue() << ")"; - return s; -} - -std::ostream &operator<<(std::ostream &s, const irr::video::SColorf &c) -{ - s << "cf32(" - << "a=" << c.getAlpha() << ",r=" << c.getRed() << ",g=" << c.getGreen() - << ",b=" << c.getBlue() << ")"; - return s; -} - -#include "util/string.h" -std::ostream &operator<<(std::ostream &s, const std::wstring &w) -{ - s << wide_to_utf8(w); - return s; -} - -std::ostream &operator<<(std::ostream &s, const Json::Value &json) -{ - s << fastWriteJson(json); - return s; -} - -std::ostream &operator<<(std::ostream &s, const Address &addr) -{ - addr.print(s); - // s << addr.getPort(); - return s; -} \ No newline at end of file diff --git a/src/log_types.h b/src/log_types.h deleted file mode 100644 index 7a24f2c90..000000000 --- a/src/log_types.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Freeminer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . -*/ - -#ifndef LOG_TYPES_HEADER -#define LOG_TYPES_HEADER - -//#include "log.h" //for replacing log.h to log_types.h in includes - -#include "irr_v2d.h" -#include "irr_v3d.h" - -#include -std::ostream &operator<<(std::ostream &s, const v2s16 &p); -std::ostream &operator<<(std::ostream &s, const v2s32 &p); -std::ostream &operator<<(std::ostream &s, const v2f &p); -std::ostream &operator<<(std::ostream &s, const v3pos_t &p); -std::ostream &operator<<(std::ostream &s, const v3f &p); -#if USE_OPOS64 -std::ostream &operator<<(std::ostream &s, const v3opos_t &p); -#endif - -#include -std::ostream &operator<<(std::ostream &s, const irr::video::SColor &c); -std::ostream &operator<<(std::ostream &s, const irr::video::SColorf &c); - -#include -std::ostream &operator<<(std::ostream &s, const std::map &p); - -std::ostream &operator<<(std::ostream &s, const std::wstring &w); - -namespace Json -{ -class Value; -}; - -//std::ostream &operator<<(std::ostream &s, const Json::Value &json); - -class Address; -std::ostream &operator<<(std::ostream &s, const Address &addr); - -#endif \ No newline at end of file diff --git a/src/network/lan.cpp b/src/network/lan.cpp index e7f163395..63ca5e8f9 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -31,7 +31,7 @@ along with Freeminer. If not, see . #include "debug.h" #include "json/json.h" #include "porting.h" -#include "threading/thread_vector.h" +#include "threading/thread.h" #include "threading/concurrent_map.h" #include "network/address.h" @@ -71,13 +71,13 @@ typedef int socket_t; const static unsigned short int adv_port = 29998; static std::string ask_str; -lan_adv::lan_adv() : thread_vector("lan_adv") +lan_adv::lan_adv() : Thread("lan_adv") { } void lan_adv::ask() { - reanimate(); + if (!isRunning()) start(); if (ask_str.empty()) { Json::Value j; @@ -169,14 +169,15 @@ void lan_adv::send_string(const std::string &str) void lan_adv::serve(unsigned short port) { server_port = port; - restart(); + if (isRunning()) stop(); + start(); } void *lan_adv::run() { BEGIN_DEBUG_EXCEPTION_HANDLER; - reg("LanAdv" + (server_port ? std::string("Server") : std::string("Client"))); + setName("LanAdv" + (server_port ? std::string("Server") : std::string("Client"))); UDPSocket socket_recv(true); int set_option_off = 0, set_option_on = 1; diff --git a/src/network/lan.h b/src/network/lan.h index 6dafab2a0..c4c2eb07f 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -22,11 +22,11 @@ along with Freeminer. If not, see . #include #include #include -#include "threading/thread_vector.h" +#include "threading/thread.h" #include "threading/concurrent_map.h" -class lan_adv : public thread_vector +class lan_adv : public Thread { public: void *run(); diff --git a/src/server/serverlist.cpp b/src/server/serverlist.cpp index 1165ae9da..a59284f4c 100644 --- a/src/server/serverlist.cpp +++ b/src/server/serverlist.cpp @@ -50,18 +50,6 @@ void lan_get() { lan_adv_client.ask(); } -/* - if (ask_str.empty()) { - Json::Value j; - j["cmd"] = "ask"; - j["proto_min"] = Server::getProtocolVersionMin(); - j["proto_max"] = Server::getProtocolVersionMax(); - ask_str = fastWriteJson(j); - - }; - lan_adv_client.send_string(ask_str); -*/ - bool lan_fresh() { auto result = lan_adv_client.fresh.load(); lan_adv_client.fresh = false; diff --git a/src/threading/CMakeLists.txt b/src/threading/CMakeLists.txt index 25c7e955c..d7549fe02 100644 --- a/src/threading/CMakeLists.txt +++ b/src/threading/CMakeLists.txt @@ -3,6 +3,5 @@ set(JTHREAD_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/lock.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/thread_vector.cpp PARENT_SCOPE) diff --git a/src/threading/thread_vector.cpp b/src/threading/thread_vector.cpp deleted file mode 100644 index 5d206f58c..000000000 --- a/src/threading/thread_vector.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "thread_vector.h" -#include "fm_porting.h" -#include "log.h" -#include "porting.h" - -thread_vector::thread_vector(const std::string &name, int priority) : - m_name(name), m_priority(priority) -{ - request_stop = false; -}; - -thread_vector::~thread_vector() -{ - join(); -}; - -void thread_vector::func() -{ - reg(); - run(); -}; - -void thread_vector::reg(const std::string &name, int priority) -{ - if (!name.empty()) - m_name = name; - - porting::setThreadName(m_name.c_str()); - g_logger.registerThread(m_name); - - if (priority) - m_priority = priority; - if (m_priority) - porting::setThreadPriority(m_priority); -}; - -void thread_vector::start(const size_t n) -{ -#if !NDEBUG - infostream << "start thread " << m_name << " n=" << n << std::endl; -#endif - request_stop = false; - for (size_t i = 0; i < n; ++i) { - workers.emplace_back(&thread_vector::func, this); - } -} - -void thread_vector::stop() -{ - request_stop = true; -} - -void thread_vector::join() -{ - stop(); - for (auto &worker : workers) { - try { - if (worker.joinable()) { - worker.join(); - } - } catch (...) { - } - } - workers.clear(); -} - -void thread_vector::restart(size_t n) -{ - join(); - start(n); -} -void thread_vector::reanimate(size_t n) -{ - if (workers.empty()) { - start(n); - } -} - -void thread_vector::sleep(const int seconds) -{ - for (int i = 0; i <= seconds; ++i) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - if (request_stop) { - return; - } - } -} - -// JThread compat: -bool thread_vector::stopRequested() -{ - return request_stop; -} -bool thread_vector::isRunning() -{ - return !workers.empty(); -} -void thread_vector::wait() -{ - join(); -}; -void thread_vector::kill() -{ - join(); -}; -void *thread_vector::run() -{ - return nullptr; -}; - -bool thread_vector::isCurrentThread() -{ - auto thread_me = std::hash()(std::this_thread::get_id()); - for (auto &worker : workers) - if (thread_me == std::hash()(worker.get_id())) - return true; - return false; -} diff --git a/src/threading/thread_vector.h b/src/threading/thread_vector.h deleted file mode 100644 index 8172dd7b6..000000000 --- a/src/threading/thread_vector.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -class thread_vector { -public: - std::vector workers; - std::atomic_bool request_stop; - - thread_vector(const std::string &name = "Unnamed", int priority = 0); - virtual ~thread_vector(); - - virtual void func(); - - void reg (const std::string &name = "", int priority = 0); - void start (const size_t n = 1); - void restart (const size_t n = 1); - void reanimate (const size_t n = 1); - void stop (); - void join (); - - void sleep(const int second); -// Thread compat: - - bool stopRequested(); - bool isRunning(); - void wait(); - void kill(); - virtual void * run() = 0; - bool isCurrentThread(); -protected: - std::string m_name; - int m_priority = 0; -}; \ No newline at end of file From cacaaec14ecdff699723c03db2f2a95a400ab271 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 27 Jun 2024 17:48:42 -0500 Subject: [PATCH 03/24] Remove unneeded freeminer code. --- src/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00d5d0ca5..e10f392eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -417,8 +417,6 @@ set(common_SRCS light.cpp lighting.cpp log.cpp - #log_types.cpp - main.cpp map.cpp map_settings_manager.cpp mapblock.cpp From 6f9bbea49a8c8105d48080d0ceaa010d5fb8f332 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 27 Jun 2024 18:46:35 -0500 Subject: [PATCH 04/24] Add main.cpp to CMakeLists.txt --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e10f392eb..955bf05f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -417,6 +417,7 @@ set(common_SRCS light.cpp lighting.cpp log.cpp + main.cpp map.cpp map_settings_manager.cpp mapblock.cpp From a15e0d09cdb8f9e126e750ceb6c411392dd36055 Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Thu, 27 Jun 2024 19:14:36 -0500 Subject: [PATCH 05/24] Possible fix for check errors. --- src/network/lan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/lan.h b/src/network/lan.h index c4c2eb07f..ea058f1ae 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -19,7 +19,7 @@ along with Freeminer. If not, see . #pragma once -#include +#include "json/json.h" #include #include #include "threading/thread.h" @@ -43,4 +43,4 @@ public: private: unsigned short server_port = 0; -}; \ No newline at end of file +}; From e0cdc715aa28c46938f836a70324734ec6b3766d Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:37:11 -0500 Subject: [PATCH 06/24] Fix accidental change to debug.h --- src/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.h b/src/debug.h index 3a16c9dde..80497f2b3 100644 --- a/src/debug.h +++ b/src/debug.h @@ -78,7 +78,7 @@ void debug_set_exception_handler(); These should be put into every thread */ -#if CATCH_UNHANDLED_EXCEPTIONS == 0 +#if CATCH_UNHANDLED_EXCEPTIONS == 1 #define BEGIN_DEBUG_EXCEPTION_HANDLER try { #define END_DEBUG_EXCEPTION_HANDLER \ } catch (std::exception &e) { \ From fac62dc3d1f9f1406ed1d5c94c2e1bb7e23f4249 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Sat, 6 Jul 2024 14:22:37 -0500 Subject: [PATCH 07/24] Switch from broadcast to multicast (ipv4) --- builtin/mainmenu/tab_online.lua | 25 ++++++----- src/network/lan.cpp | 78 +++++++++++++++++++++++---------- src/network/lan.h | 1 + 3 files changed, 72 insertions(+), 32 deletions(-) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index e1653dce1..49c175e7c 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -17,32 +17,31 @@ local function get_sorted_servers() local servers = { + lan = {}, fav = {}, public = {}, incompatible = {} } + local merged_serverlist = table.copy(serverlistmgr.servers) + --Special thanks to proller for letting use use the get_lan_servers function. if minetest.settings:get_bool("serverlist_lan") then if core.get_lan_servers then - servers.lan = core.get_lan_servers(); - - for _, server in ipairs(servers.lan) do + local lan = core.get_lan_servers() + for _, server in ipairs(lan) do server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max) + server.is_local = true + table.insert(merged_serverlist, server) end else print("core.get_lan_servers isn't defined.") - servers.lan = {} end - else - servers.lan = {} end - print(dump(servers.lan)) - local favs = serverlistmgr.get_favorites() local taken_favs = {} - local result = menudata.search_result or serverlistmgr.servers + local result = menudata.search_result or merged_serverlist for _, server in ipairs(result) do server.is_favorite = false for index, fav in ipairs(favs) do @@ -56,7 +55,11 @@ local function get_sorted_servers() if server.is_favorite then table.insert(servers.fav, server) elseif server.is_compatible then - table.insert(servers.public, server) + if server.is_local then + table.insert(servers.lan, server) + else + table.insert(servers.public, server) + end else table.insert(servers.incompatible, server) end @@ -389,6 +392,8 @@ local function main_button_handler(tabview, fields, name, tabdata) serverlistmgr.add_favorite(server) + print("Adding this server to favorites: \n"..dump(server)) + gamedata.servername = server.name gamedata.serverdescription = server.description diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 63ca5e8f9..7c833f091 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -68,13 +68,34 @@ typedef int socklen_t; typedef int socket_t; #endif +const char* adv_multicast_addr = "224.1.1.1"; const static unsigned short int adv_port = 29998; static std::string ask_str; +bool use_ipv6 = true; + lan_adv::lan_adv() : Thread("lan_adv") { } +lan_adv::~lan_adv() +{ + if (!stopRequested()) { + stop(); + warningstream << "Thread Had to be forced to stop correctly." << std::endl; + } + + if (stopRequested()) warningstream << "Lan Adv Thread is stopping." << std::endl; + + if (server_port) { + Json::Value answer_json; + answer_json["port"] = server_port; + answer_json["cmd"] = "shutdown"; + send_string(fastWriteJson(answer_json)); + warningstream << "Server shut down message sent." << std::endl; + } +} + void lan_adv::ask() { if (!isRunning()) start(); @@ -94,18 +115,33 @@ void lan_adv::send_string(const std::string &str) sockaddr_in addr = {}; addr.sin_family = AF_INET; addr.sin_port = htons(adv_port); - addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); UDPSocket socket_send(false); - int set_option_on = 1; - setsockopt(socket_send.GetHandle(), SOL_SOCKET, SO_BROADCAST, - (const char *)&set_option_on, sizeof(set_option_on)); + + // Full discloser, the use of inet_proto and the mreq stucture + // were suggested by ai. + + inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr)); + + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + + setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&mreq, sizeof(mreq)); + + //int set_option_on = 2; + //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL, + // (const char *)&set_option_on, sizeof(set_option_on)); + socket_send.Send(Address(addr), str.c_str(), str.size()); } catch (const std::exception &e) { verbosestream << "udp broadcast send4 fail " << e.what() << "\n"; } std::vector scopes; -// todo: windows and android + // todo: windows and android #if HAVE_IFADDRS struct ifaddrs *ifaddr = nullptr, *ifa = nullptr; @@ -118,7 +154,7 @@ void lan_adv::send_string(const std::string &str) continue; auto sa = *((struct sockaddr_in6 *)ifa->ifa_addr); - if (sa.sin6_scope_id) + if (sa.sin6_scope_id) scopes.push_back(sa.sin6_scope_id); /*errorstream<<"in=" << ifa->ifa_name << " a="<ifa_addr)).serializeString()<<" ba=" << ifa->ifa_broadaddr <<" sc=" << sa.sin6_scope_id <<" fl=" << ifa->ifa_flags @@ -147,8 +183,8 @@ void lan_adv::send_string(const std::string &str) addr.sin6_port = htons(adv_port); UDPSocket socket_send(true); int set_option_on = 1; - setsockopt(socket_send.GetHandle(), SOL_SOCKET, SO_BROADCAST, - (const char *)&set_option_on, sizeof(set_option_on)); + //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IPV6_MULTICAST_HOPS, + // (const char *)&set_option_on, sizeof(set_option_on)); auto use_scopes = scopes; if (addr.sin6_scope_id) { use_scopes.clear(); @@ -169,7 +205,7 @@ void lan_adv::send_string(const std::string &str) void lan_adv::serve(unsigned short port) { server_port = port; - if (isRunning()) stop(); + stop(); start(); } @@ -187,8 +223,13 @@ void *lan_adv::run() setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEPORT, (const char *)&set_option_on, sizeof(set_option_on)); #endif - setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_BROADCAST, - (const char *)&set_option_on, sizeof(set_option_on)); + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + setsockopt(socket_recv.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&mreq, sizeof(mreq)); setsockopt(socket_recv.GetHandle(), IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&set_option_off, sizeof(set_option_off)); socket_recv.setTimeoutMs(200); @@ -254,11 +295,11 @@ void *lan_adv::run() server["clients"] = clients_num.load(); answer_str = fastWriteJson(server); - limiter[addr_str] = now + 3000; - UDPSocket socket_send(true); - addr.setPort(adv_port); - socket_send.Send(addr, answer_str.c_str(), answer_str.size()); + send_string(answer_str); + //UDPSocket socket_send(true); + //addr.setPort(adv_port); + //socket_send.Send(addr, answer_str.c_str(), answer_str.size()); } } else { if (p["cmd"] == "ask") { @@ -284,13 +325,6 @@ void *lan_adv::run() END_DEBUG_EXCEPTION_HANDLER; } - if (server_port) { - Json::Value answer_json; - answer_json["port"] = server_port; - answer_json["cmd"] = "shutdown"; - send_string(fastWriteJson(answer_json)); - } - END_DEBUG_EXCEPTION_HANDLER; return nullptr; diff --git a/src/network/lan.h b/src/network/lan.h index ea058f1ae..7a4215073 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -32,6 +32,7 @@ public: void *run(); lan_adv(); + ~lan_adv(); void ask(); void send_string(const std::string &str); From 7e78a5ece0dbdb314f0d0c0053c9d3e828dda0ef Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Sun, 7 Jul 2024 21:00:33 -0500 Subject: [PATCH 08/24] Alternative Solution for lan_adv Destructer --- builtin/mainmenu/tab_online.lua | 2 - src/network/lan.cpp | 182 ++++++++++++++++---------------- src/network/lan.h | 1 - src/server.cpp | 11 ++ 4 files changed, 103 insertions(+), 93 deletions(-) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 49c175e7c..c626f84d3 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -392,8 +392,6 @@ local function main_button_handler(tabview, fields, name, tabdata) serverlistmgr.add_favorite(server) - print("Adding this server to favorites: \n"..dump(server)) - gamedata.servername = server.name gamedata.serverdescription = server.description diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 7c833f091..80b4c9671 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -78,24 +78,6 @@ lan_adv::lan_adv() : Thread("lan_adv") { } -lan_adv::~lan_adv() -{ - if (!stopRequested()) { - stop(); - warningstream << "Thread Had to be forced to stop correctly." << std::endl; - } - - if (stopRequested()) warningstream << "Lan Adv Thread is stopping." << std::endl; - - if (server_port) { - Json::Value answer_json; - answer_json["port"] = server_port; - answer_json["cmd"] = "shutdown"; - send_string(fastWriteJson(answer_json)); - warningstream << "Server shut down message sent." << std::endl; - } -} - void lan_adv::ask() { if (!isRunning()) start(); @@ -111,6 +93,69 @@ void lan_adv::ask() void lan_adv::send_string(const std::string &str) { + if (g_settings->getBool("enable_ipv6")) { + std::vector scopes; + // todo: windows and android + +#if HAVE_IFADDRS + struct ifaddrs *ifaddr = nullptr, *ifa = nullptr; + if (getifaddrs(&ifaddr) < 0) { + } else { + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + auto sa = *((struct sockaddr_in6 *)ifa->ifa_addr); + if (sa.sin6_scope_id) + scopes.push_back(sa.sin6_scope_id); + + /*errorstream<<"in=" << ifa->ifa_name << " a="<ifa_addr)).serializeString()<<" ba=" << ifa->ifa_broadaddr <<" sc=" << sa.sin6_scope_id <<" fl=" << ifa->ifa_flags + //<< " bn=" << Address(*((struct sockaddr_in6*)ifa->ifa_broadaddr)).serializeString() + <<"\n"; */ + } + } + freeifaddrs(ifaddr); +#endif + + if (scopes.empty()) + scopes.push_back(0); + + struct addrinfo hints + { + }; + + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + struct addrinfo *result = nullptr; + if (!getaddrinfo("ff02::1", nullptr, &hints, &result)) { + for (auto info = result; info; info = info->ai_next) { + try { + sockaddr_in6 addr = *((struct sockaddr_in6 *)info->ai_addr); + addr.sin6_port = htons(adv_port); + UDPSocket socket_send(true); + int set_option_on = 1; + //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IPV6_MULTICAST_HOPS, + // (const char *)&set_option_on, sizeof(set_option_on)); + auto use_scopes = scopes; + if (addr.sin6_scope_id) { + use_scopes.clear(); + use_scopes.push_back(addr.sin6_scope_id); + } + for (auto &scope : use_scopes) { + addr.sin6_scope_id = scope; + socket_send.Send(Address(addr), str.c_str(), str.size()); + } + } catch (const std::exception &e) { + verbosestream << "udp broadcast send over ipv6 fail " << e.what() << "\n"; + } + } + freeaddrinfo(result); + } + } + try { sockaddr_in addr = {}; addr.sin_family = AF_INET; @@ -137,68 +182,7 @@ void lan_adv::send_string(const std::string &str) socket_send.Send(Address(addr), str.c_str(), str.size()); } catch (const std::exception &e) { - verbosestream << "udp broadcast send4 fail " << e.what() << "\n"; - } - - std::vector scopes; - // todo: windows and android - -#if HAVE_IFADDRS - struct ifaddrs *ifaddr = nullptr, *ifa = nullptr; - if (getifaddrs(&ifaddr) < 0) { - } else { - for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) - continue; - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - - auto sa = *((struct sockaddr_in6 *)ifa->ifa_addr); - if (sa.sin6_scope_id) - scopes.push_back(sa.sin6_scope_id); - - /*errorstream<<"in=" << ifa->ifa_name << " a="<ifa_addr)).serializeString()<<" ba=" << ifa->ifa_broadaddr <<" sc=" << sa.sin6_scope_id <<" fl=" << ifa->ifa_flags - //<< " bn=" << Address(*((struct sockaddr_in6*)ifa->ifa_broadaddr)).serializeString() - <<"\n"; */ - } - } - freeifaddrs(ifaddr); -#endif - - if (scopes.empty()) - scopes.push_back(0); - - struct addrinfo hints - { - }; - - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; - struct addrinfo *result = nullptr; - if (!getaddrinfo("ff02::1", nullptr, &hints, &result)) { - for (auto info = result; info; info = info->ai_next) { - try { - sockaddr_in6 addr = *((struct sockaddr_in6 *)info->ai_addr); - addr.sin6_port = htons(adv_port); - UDPSocket socket_send(true); - int set_option_on = 1; - //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IPV6_MULTICAST_HOPS, - // (const char *)&set_option_on, sizeof(set_option_on)); - auto use_scopes = scopes; - if (addr.sin6_scope_id) { - use_scopes.clear(); - use_scopes.push_back(addr.sin6_scope_id); - } - for (auto &scope : use_scopes) { - addr.sin6_scope_id = scope; - socket_send.Send(Address(addr), str.c_str(), str.size()); - } - } catch (const std::exception &e) { - verbosestream << "udp broadcast send6 fail " << e.what() << "\n"; - } - } - freeaddrinfo(result); + verbosestream << "udp broadcast send over ipv4 fail " << e.what() << "\n"; } } @@ -213,9 +197,9 @@ void *lan_adv::run() { BEGIN_DEBUG_EXCEPTION_HANDLER; - setName("LanAdv" + (server_port ? std::string("Server") : std::string("Client"))); + setName("lan_adv " + (server_port ? std::string("server") : std::string("client"))); + UDPSocket socket_recv(g_settings->getBool("enable_ipv6")); - UDPSocket socket_recv(true); int set_option_off = 0, set_option_on = 1; setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEADDR, (const char *)&set_option_on, sizeof(set_option_on)); @@ -233,16 +217,27 @@ void *lan_adv::run() setsockopt(socket_recv.GetHandle(), IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&set_option_off, sizeof(set_option_off)); socket_recv.setTimeoutMs(200); - try { - socket_recv.Bind(Address(in6addr_any, adv_port)); - } catch (const std::exception &e) { - warningstream << m_name << ": cant bind ipv6 address [" << e.what() - << "], trying ipv4. " << std::endl; + + if (g_settings->getBool("enable_ipv6")) { + try { + socket_recv.Bind(Address(in6addr_any, adv_port)); + } catch (const std::exception &e) { + warningstream << m_name << ": cant bind ipv6 address [" << e.what() + << "], trying ipv4. " << std::endl; + try { + socket_recv.Bind(Address((u32)INADDR_ANY, adv_port)); + } catch (const std::exception &e) { + warningstream << m_name << ": cant bind ipv4 too [" << e.what() << "]" + << std::endl; + return nullptr; + } + } + } else { try { socket_recv.Bind(Address((u32)INADDR_ANY, adv_port)); } catch (const std::exception &e) { - warningstream << m_name << ": cant bind ipv4 too [" << e.what() << "]" - << std::endl; + warningstream << m_name << ": cant bind ipv4 [" << e.what() << "]" + << std::endl; return nullptr; } } @@ -273,7 +268,7 @@ void *lan_adv::run() send_string(fastWriteJson(server)); } - while (!stopRequested()) { + while (isRunning() && !stopRequested()) { BEGIN_DEBUG_EXCEPTION_HANDLER; Address addr; int rlen = socket_recv.Receive(addr, buffer, packet_maxsize); @@ -325,6 +320,13 @@ void *lan_adv::run() END_DEBUG_EXCEPTION_HANDLER; } + if (server_port) { + Json::Value answer_json; + answer_json["port"] = server_port; + answer_json["cmd"] = "shutdown"; + send_string(fastWriteJson(answer_json)); + } + END_DEBUG_EXCEPTION_HANDLER; return nullptr; diff --git a/src/network/lan.h b/src/network/lan.h index 7a4215073..ea058f1ae 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -32,7 +32,6 @@ public: void *run(); lan_adv(); - ~lan_adv(); void ask(); void send_string(const std::string &str); diff --git a/src/server.cpp b/src/server.cpp index f9dc6f811..75b8b165e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -412,6 +412,17 @@ Server::~Server() delete m_unsent_map_edit_queue.front(); m_unsent_map_edit_queue.pop(); } + + if (g_settings->getBool("serverlist_lan")) { + lan_adv_server.stop(); + + while (lan_adv_server.isRunning()) { + // Wait until the lan_adv_server thread has finished. + // This is so that its thread destructor doesn't kill the thread + // before it sends the 'shutdown' command to remove this server's + // server info from the serverlist of local clients. + } + } } void Server::init() From 4cbf6f514512db80b4eb46871947986296a715e2 Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:11:35 -0500 Subject: [PATCH 09/24] Revert CIrrDeviceSDL.cpp --- irr/src/CIrrDeviceSDL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index eac3a9344..2f72e6223 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -704,7 +704,7 @@ bool CIrrDeviceSDL::run() { os::Timer::tick(); - SEvent irrevent{}; + SEvent irrevent; SDL_Event SDL_event; while (!Close && wrap_PollEvent(&SDL_event)) { From 3ac1527e1f2c695e0c787519a8bd63506018aecd Mon Sep 17 00:00:00 2001 From: proller Date: Sat, 27 Jul 2024 13:59:44 +0200 Subject: [PATCH 10/24] Dont use fm stuff --- src/network/lan.cpp | 4 +- src/network/lan.h | 7 +- src/script/lua_api/l_mainmenu.cpp | 1 + src/threading/concurrent_map.h | 209 ------------------------------ src/threading/lock.cpp | 131 ------------------- src/threading/lock.h | 164 ----------------------- 6 files changed, 9 insertions(+), 507 deletions(-) delete mode 100644 src/threading/concurrent_map.h delete mode 100644 src/threading/lock.cpp delete mode 100644 src/threading/lock.h diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 80b4c9671..7762edfde 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -30,9 +30,10 @@ along with Freeminer. If not, see . #include "server/serverlist.h" #include "debug.h" #include "json/json.h" +#include +#include #include "porting.h" #include "threading/thread.h" -#include "threading/concurrent_map.h" #include "network/address.h" //copypaste from ../socket.cpp @@ -303,6 +304,7 @@ void *lan_adv::run() if (p["port"].isInt()) { p["address"] = addr_str; auto key = addr_str + ":" + p["port"].asString(); + std::unique_lock lock(mutex); if (p["cmd"].asString() == "shutdown") { //infostream << "server shutdown " << key << "\n"; collected.erase(key); diff --git a/src/network/lan.h b/src/network/lan.h index ea058f1ae..085a597a2 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -20,10 +20,11 @@ along with Freeminer. If not, see . #pragma once #include "json/json.h" +#include +#include #include #include #include "threading/thread.h" -#include "threading/concurrent_map.h" class lan_adv : public Thread @@ -37,7 +38,9 @@ public: void serve(unsigned short port); - concurrent_map collected; + std::map collected; + std::shared_mutex mutex; + std::atomic_bool fresh; std::atomic_int clients_num; diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 6a637f7d7..f7ba929cc 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1101,6 +1101,7 @@ int ModApiMainMenu::l_get_lan_servers(lua_State *L) int top = lua_gettop(L); unsigned int index = 1; + std::shared_lock lock(ServerList::lan_adv_client.mutex); for (const auto &server : ServerList::lan_adv_client.collected) { lua_pushnumber(L, index); diff --git a/src/threading/concurrent_map.h b/src/threading/concurrent_map.h deleted file mode 100644 index c07971d59..000000000 --- a/src/threading/concurrent_map.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -Copyright (C) 2024 proller -*/ - -/* -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Freeminer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . -*/ - -#pragma once - -#include - -#include "lock.h" - -template , - class Allocator = std::allocator>> -class concurrent_map_ : public std::map, public LOCKER -{ -public: - typedef typename std::map full_type; - typedef Key key_type; - typedef T mapped_type; - - mapped_type &operator[](const key_type &k) = delete; - mapped_type &operator[](key_type &&k) = delete; - - mapped_type nothing = {}; - - template - mapped_type& get(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - - //if (!full_type::contains(std::forward(args)...)) - if (full_type::find(std::forward(args)...) == full_type::end()) - return nothing; - - return full_type::operator[](std::forward(args)...); - } - - template - decltype(auto) at(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::at(std::forward(args)...); - } - - template - decltype(auto) assign(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::assign(std::forward(args)...); - } - - template - decltype(auto) insert(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::insert(std::forward(args)...); - } - - template - decltype(auto) emplace(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::emplace(std::forward(args)...); - } - - template - decltype(auto) emplace_try(Args &&...args) - { - auto lock = LOCKER::try_lock_unique_rec(); - if (!lock->owns_lock()) - return false; - return full_type::emplace(std::forward(args)...).second; - } - - template - decltype(auto) insert_or_assign(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::insert_or_assign(std::forward(args)...); - } - - template - decltype(auto) empty(Args &&...args) const noexcept - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::empty(std::forward(args)...); - } - - template - decltype(auto) size(Args &&...args) const - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::size(std::forward(args)...); - } - - template - decltype(auto) count(Args &&...args) const - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::count(std::forward(args)...); - } - - template - decltype(auto) contains(Args &&...args) const - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::contains(std::forward(args)...); - } - - template - decltype(auto) find(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::find(std::forward(args)...); - } - - template - decltype(auto) begin(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::begin(std::forward(args)...); - } - - template - decltype(auto) rbegin(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::rbegin(std::forward(args)...); - } - - template - decltype(auto) end(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::end(std::forward(args)...); - } - - template - decltype(auto) rend(Args &&...args) - { - auto lock = LOCKER::lock_shared_rec(); - return full_type::rend(std::forward(args)...); - } - - - template - decltype(auto) erase(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::erase(std::forward(args)...); - } - - template - decltype(auto) clear(Args &&...args) - { - auto lock = LOCKER::lock_unique_rec(); - return full_type::clear(std::forward(args)...); - } -}; - -template , - class Allocator = std::allocator>> -using concurrent_map = concurrent_map_, Key, T, Compare, Allocator>; - -template , class Allocator = std::allocator>> -using concurrent_shared_map = concurrent_map_; - -#if ENABLE_THREADS - -template , - class Allocator = std::allocator>> -using maybe_concurrent_map = concurrent_map; - -#else - -template , - class Allocator = std::allocator>> -class not_concurrent_map : public std::map, - public dummy_locker -{ -public: - typedef typename std::map full_type; - typedef Key key_type; - typedef T mapped_type; - - mapped_type &get(const key_type &k) { return full_type::operator[](k); } -}; - -template , - class Allocator = std::allocator>> -using maybe_concurrent_map = not_concurrent_map; - -#endif \ No newline at end of file diff --git a/src/threading/lock.cpp b/src/threading/lock.cpp deleted file mode 100644 index d80055447..000000000 --- a/src/threading/lock.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "lock.h" -#include "log.h" -#include "profiler.h" - -#if !defined(NDEBUG) && !defined(LOCK_PROFILE) -//#define LOCK_PROFILE 1 -#endif - -#if LOCK_PROFILE -#define SCOPE_PROFILE(a) ScopeProfiler scp___(g_profiler, "Lock: " a); -#else -#define SCOPE_PROFILE(a) -#endif - -template -recursive_lock::recursive_lock(MUTEX & mtx, std::atomic & thread_id_, bool try_lock): - thread_id(thread_id_) { - auto thread_me = std::hash()(std::this_thread::get_id()); - if(thread_me != thread_id) { - if (try_lock) { - SCOPE_PROFILE("try_lock"); - lock = new GUARD(mtx, try_to_lock); - if (lock->owns_lock()) { - thread_id = thread_me; - return; - } else { -#if LOCK_PROFILE - g_profiler->add("Lock: try_lock fail", 1); -#endif - //infostream<<"not locked "<<" thread="<add("Lock: recursive", 1); -#endif - } - lock = nullptr; -} - -template -recursive_lock::~recursive_lock() { - unlock(); -} - -template -bool recursive_lock::owns_lock() { - if (lock) - return lock; - auto thread_me = std::hash()(std::this_thread::get_id()); - return thread_id == thread_me; -} - -template -void recursive_lock::unlock() { - if(lock) { - thread_id = 0; - lock->unlock(); - delete lock; - lock = nullptr; - } -} - - -template -locker::locker() { - thread_id = 0; -} - -template -std::unique_ptr locker::lock_unique() { - return std::make_unique(mtx); -} - -template -std::unique_ptr locker::try_lock_unique() { - SCOPE_PROFILE("locker::try_lock_unique"); - return std::make_unique(mtx, std::try_to_lock); -} - -template -std::unique_ptr locker::lock_shared() const { - SCOPE_PROFILE("locker::lock_shared"); - return std::make_unique(mtx); -} - -template -std::unique_ptr locker::try_lock_shared() { - SCOPE_PROFILE("locker::try_lock_shared"); - return std::make_unique(mtx, std::try_to_lock); -} - -template -std::unique_ptr> locker::lock_unique_rec() const { - SCOPE_PROFILE("locker::lock_unique_rec"); - return std::make_unique(mtx, thread_id); -} - -template -std::unique_ptr> locker::try_lock_unique_rec() { - SCOPE_PROFILE("locker::try_lock_unique_rec"); - return std::make_unique(mtx, thread_id, true); -} - -template -std::unique_ptr> locker::lock_shared_rec() const { - SCOPE_PROFILE("locker::lock_shared_rec"); - return std::make_unique(mtx, thread_id); -} - -template -std::unique_ptr> locker::try_lock_shared_rec() { - SCOPE_PROFILE("locker::try_lock_shared_rec"); - return std::make_unique(mtx, thread_id, true); -} - - -template class recursive_lock>; -template class locker<>; -#if LOCK_TWO -template class recursive_lock; -template class recursive_lock, try_shared_mutex>; - -template class locker, std::shared_lock>; -#endif \ No newline at end of file diff --git a/src/threading/lock.h b/src/threading/lock.h deleted file mode 100644 index a3cd43e29..000000000 --- a/src/threading/lock.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Freeminer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . -*/ - -#pragma once - -#include -#include -#include -#include - -#include "../config.h" - -#ifdef _WIN32 - -//#include "../threading/mutex.h" -using use_mutex = std::mutex; -using try_shared_mutex = use_mutex; -using try_shared_lock = std::unique_lock; -using unique_lock = std::unique_lock; -const auto try_to_lock = std::try_to_lock; - -#else - -typedef std::mutex use_mutex; - - -#if USE_BOOST // not finished - -//#include -#include -//#include -typedef boost::shared_mutex try_shared_mutex; -typedef boost::shared_lock try_shared_lock; -typedef boost::unique_lock unique_lock; -const auto try_to_lock = boost::try_to_lock; -#define LOCK_TWO 1 - -#elif HAVE_SHARED_MUTEX -//#elif __cplusplus >= 201305L - -#include -using try_shared_mutex = std::shared_mutex; -using try_shared_lock = std::shared_lock; -using unique_lock = std::unique_lock; -const auto try_to_lock = std::try_to_lock; -#define LOCK_TWO 1 - -#else - -using try_shared_mutex = use_mutex; -using try_shared_lock = std::unique_lock ; -using unique_lock = std::unique_lock ; -const auto try_to_lock = std::try_to_lock; -#endif - -#endif - - -// http://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads -/* uncomment when need -#include -class semaphore { -private: - std::mutex mtx; - std::condition_variable cv; - int count; - -public: - semaphore(int count_ = 0):count(count_){;} - void notify() { - std::unique_lock lck(mtx); - ++count; - cv.notify_one(); - } - void wait() { - std::unique_lock lck(mtx); - while(count == 0){ - cv.wait(lck); - } - count--; - } -}; -*/ - -template -class recursive_lock { -public: - GUARD * lock; - std::atomic & thread_id; - recursive_lock(MUTEX & mtx, std::atomic & thread_id_, bool try_lock = false); - ~recursive_lock(); - bool owns_lock(); - void unlock(); -}; - -template , class shared_lock = std::unique_lock > -class locker { -public: - using lock_rec_shared = recursive_lock; - using lock_rec_unique = recursive_lock; - - mutable mutex mtx; - mutable std::atomic thread_id; - - locker(); - std::unique_ptr lock_unique(); - std::unique_ptr try_lock_unique(); - std::unique_ptr lock_shared() const; - std::unique_ptr try_lock_shared(); - std::unique_ptr lock_unique_rec() const; - std::unique_ptr try_lock_unique_rec(); - std::unique_ptr lock_shared_rec() const; - std::unique_ptr try_lock_shared_rec(); -}; - -using shared_locker = locker; - -class dummy_lock { -public: - ~dummy_lock() {}; //no unused variable warning - bool owns_lock() {return true;} - bool operator!() {return true;} - dummy_lock * operator->() {return this; } - void unlock() {}; -}; - -class dummy_locker { -public: - dummy_lock lock_unique() { return {}; }; - dummy_lock try_lock_unique() { return {}; }; - dummy_lock lock_shared() { return {}; }; - dummy_lock try_lock_shared() { return {}; }; - dummy_lock lock_unique_rec() { return {}; }; - dummy_lock try_lock_unique_rec() { return {}; }; - dummy_lock lock_shared_rec() { return {}; }; - dummy_lock try_lock_shared_rec() { return {}; }; -}; - - -#if ENABLE_THREADS - -using maybe_locker = locker<>; -using maybe_shared_locker = shared_locker; - -#else - -using maybe_locker = dummy_locker; -using maybe_shared_locker = dummy_locker; - -#endif \ No newline at end of file From 4188ca14332b4e20549fdcc2f33e5ef62a9cd1cc Mon Sep 17 00:00:00 2001 From: proller Date: Sun, 28 Jul 2024 15:51:22 +0200 Subject: [PATCH 11/24] fix --- src/threading/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/threading/CMakeLists.txt b/src/threading/CMakeLists.txt index d7549fe02..8f86158be 100644 --- a/src/threading/CMakeLists.txt +++ b/src/threading/CMakeLists.txt @@ -2,6 +2,5 @@ set(JTHREAD_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/event.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lock.cpp PARENT_SCOPE) From 327049e8e95aa097a4bb0cf07c60b53b87bb3530 Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Tue, 3 Sep 2024 02:45:08 -0500 Subject: [PATCH 12/24] Update CMakeLists.txt Fix a merge conflict error? --- src/network/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 99bc2b0ee..b8fafce35 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -1,7 +1,6 @@ set(common_network_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/address.cpp ${CMAKE_CURRENT_SOURCE_DIR}/connection.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/connectionthreads.cpp ${CMAKE_CURRENT_SOURCE_DIR}/lan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mtp/impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mtp/threads.cpp From 0e110c311ec26700585ae89846f2939d9000b7d1 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Fri, 27 Sep 2024 21:41:33 -0500 Subject: [PATCH 13/24] Fix Whitespace pr check issues --- src/network/lan.cpp | 6 +----- src/script/lua_api/l_mainmenu.cpp | 2 +- src/server.cpp | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 7762edfde..60b663b12 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -163,16 +163,12 @@ void lan_adv::send_string(const std::string &str) addr.sin_port = htons(adv_port); UDPSocket socket_send(false); - // Full discloser, the use of inet_proto and the mreq stucture - // were suggested by ai. - inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr)); struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); mreq.imr_interface.s_addr = htonl(INADDR_ANY); - setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); @@ -191,7 +187,7 @@ void lan_adv::serve(unsigned short port) { server_port = port; stop(); - start(); + start(); } void *lan_adv::run() diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 4ec1fc316..c7f016a8d 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1120,7 +1120,7 @@ int ModApiMainMenu::l_get_lan_servers(lua_State *L) lua_pushstring(L, field_name.c_str()); if (server.second[field_name].isString()) lua_pushstring(L, server.second[field_name].asCString()); - else if (server.second[field_name].isConvertibleTo(Json::realValue)) + else if (server.second[field_name].isConvertibleTo(Json::realValue)) lua_pushnumber(L, server.second[field_name].asDouble()); else lua_pushnil(L); diff --git a/src/server.cpp b/src/server.cpp index fc7b7f8c7..7ce21acab 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -420,7 +420,7 @@ Server::~Server() // Wait until the lan_adv_server thread has finished. // This is so that its thread destructor doesn't kill the thread // before it sends the 'shutdown' command to remove this server's - // server info from the serverlist of local clients. + // server info from the serverlist of local clients. } } } From 981e1b776667f783917e9c4b651a499ca57067a1 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Fri, 27 Sep 2024 22:40:04 -0500 Subject: [PATCH 14/24] Update Citations --- builtin/mainmenu/tab_online.lua | 1 - src/network/lan.cpp | 24 +++++++++++------------- src/network/lan.h | 22 +++++++++++----------- src/script/lua_api/l_mainmenu.cpp | 5 ----- src/script/lua_api/l_mainmenu.h | 7 +------ src/server/serverlist.cpp | 6 ------ src/server/serverlist.h | 5 ----- 7 files changed, 23 insertions(+), 47 deletions(-) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index c626f84d3..129e939e7 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -25,7 +25,6 @@ local function get_sorted_servers() local merged_serverlist = table.copy(serverlistmgr.servers) - --Special thanks to proller for letting use use the get_lan_servers function. if minetest.settings:get_bool("serverlist_lan") then if core.get_lan_servers then local lan = core.get_lan_servers() diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 60b663b12..8a0f09780 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -1,22 +1,20 @@ /* -Copyright (C) 2016 proller -*/ +Minetest +Copyright (C) 2024 proller and contributors. -/* -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. -Freeminer is distributed in the hope that it will be useful, +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "network/lan.h" diff --git a/src/network/lan.h b/src/network/lan.h index 085a597a2..bd49c40f6 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -1,20 +1,20 @@ /* -Copyright (C) 2016 proller +Minetest +Copyright (C) 2024 proller and contributors. -This file is part of Freeminer. - -Freeminer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. -Freeminer is distributed in the hope that it will be useful, +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License -along with Freeminer. If not, see . +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index c7f016a8d..8ee438c64 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1092,11 +1092,6 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L) /******************************************************************************/ -/* -ModApiMainMenu::l_ask_lan_servers, ModApiMainMenu::l_get_lan_servers -by proller , special thanks for letting us use them. -*/ - int ModApiMainMenu::l_ask_lan_servers(lua_State *L) { ServerList::lan_get(); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 38d7c50cc..058506436 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -60,12 +60,7 @@ private: */ static bool mayModifyPath(std::string path); - //lan - - /* - ModApiMainMenu::l_ask_lan_servers, ModApiMainMenu::l_get_lan_servers - by proller , special thanks for letting us use it. - */ + //lan discovery static int l_ask_lan_servers(lua_State *L); diff --git a/src/server/serverlist.cpp b/src/server/serverlist.cpp index 4ee90b2ea..9b06c35fe 100644 --- a/src/server/serverlist.cpp +++ b/src/server/serverlist.cpp @@ -34,12 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc., namespace ServerList { -/* -Special thanks to proller for -letting us use the methods lan_get() and lan_fresh() -as well as the lan_adv class. -*/ - static std::string ask_str; lan_adv lan_adv_client; diff --git a/src/server/serverlist.h b/src/server/serverlist.h index 568337278..87518401c 100644 --- a/src/server/serverlist.h +++ b/src/server/serverlist.h @@ -29,11 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc., namespace ServerList { - /* - Special thanks to proller for - letting us use the methods lan_get() and lan_fresh() - as well as the lan_adv class. - */ extern lan_adv lan_adv_client; void lan_get(); bool lan_fresh(); From 0738190a33b5b465c849a59a0d93dd2aaf6253b2 Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Sun, 29 Dec 2024 12:59:39 -0600 Subject: [PATCH 15/24] Fix Bug from missing obsolete def "SERVER_PROTOCOL_VERSION_MAX" --- src/network/lan.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 8a0f09780..a70105873 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -249,8 +249,7 @@ void *lan_adv::run() bool strict_checking = g_settings->getBool("strict_protocol_version_checking"); server["proto_min"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN; - server["proto_max"] = - strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX; + server["proto_max"] = LATEST_PROTOCOL_VERSION; server["url"] = g_settings->get("server_url"); server["creative"] = g_settings->getBool("creative_mode"); server["damage"] = g_settings->getBool("enable_damage"); @@ -326,4 +325,4 @@ void *lan_adv::run() END_DEBUG_EXCEPTION_HANDLER; return nullptr; -} \ No newline at end of file +} From e27bd6a9aedfd1bc083bfe1849458dc065f13cef Mon Sep 17 00:00:00 2001 From: DustyBagel <150477174+DustyBagel@users.noreply.github.com> Date: Sun, 29 Dec 2024 13:02:27 -0600 Subject: [PATCH 16/24] Fix WhiteSpace Check failure in l_mainmenu.h --- src/script/lua_api/l_mainmenu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index bf187f610..770ae2de9 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -36,7 +36,7 @@ private: * @return bool value of requested variable */ static int getBoolData(lua_State *L, const std::string &name ,bool& valid); - + /** * Checks if a path may be modified. Paths in the temp directory or the user * games, mods, textures, or worlds directories may be modified. From 935b08ac03d4392f300896464b4481f702821313 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 02:29:43 -0600 Subject: [PATCH 17/24] Clean up Lan Servers being added to serverlistmgr.servers --- builtin/mainmenu/serverlistmgr.lua | 2 +- builtin/mainmenu/tab_online.lua | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua index a744fd885..35ae65758 100644 --- a/builtin/mainmenu/serverlistmgr.lua +++ b/builtin/mainmenu/serverlistmgr.lua @@ -22,7 +22,7 @@ serverlistmgr = { -- list of locally favorites servers favorites = nil, - -- list of servers fetched from public list + -- list of servers fetched from public list and local servers servers = nil, } diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index df76c9652..4d55b46c8 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -23,24 +23,21 @@ local function get_sorted_servers() incompatible = {} } - local merged_serverlist = table.copy(serverlistmgr.servers) + local serverlist = table.copy(serverlistmgr.servers) if minetest.settings:get_bool("serverlist_lan") then - if core.get_lan_servers then - local lan = core.get_lan_servers() - for _, server in ipairs(lan) do - server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max) - server.is_local = true - table.insert(merged_serverlist, server) - end - else - print("core.get_lan_servers isn't defined.") + local lan_servers = core.get_lan_servers() + + for _, server in ipairs(lan_servers) do + server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max) + server.is_local = true + table.insert(serverlist, server) end end local favs = serverlistmgr.get_favorites() local taken_favs = {} - local result = menudata.search_result or merged_serverlist + local result = menudata.search_result or serverlist for _, server in ipairs(result) do server.is_favorite = false for index, fav in ipairs(favs) do From a624ad5cee2fd907beb31b46acf01121a9ee462d Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 02:38:01 -0600 Subject: [PATCH 18/24] Fix server_annonce_send_players Broken Setting --- builtin/settingtypes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 356202d30..21e0b5501 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -807,7 +807,7 @@ server_url (Server URL) string https://game.example.net server_announce (Announce server) bool false # Send names of online players to the serverlist. If disabled only the player count is revealed. -server_announce_send_players (Send player names to the server list) bool tru +server_announce_send_players (Send player names to the server list) bool true # Make local servers visible to local clients. serverlist_lan (Show local servers) bool true From 6c614eb0dc05fad07ff5fb3cda32a5f1f7cadf09 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 16:20:46 -0600 Subject: [PATCH 19/24] Switch Minetest to Luanti --- src/network/lan.cpp | 2 +- src/network/lan.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index a70105873..c2a399ffe 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -1,5 +1,5 @@ /* -Minetest +Luanti Copyright (C) 2024 proller and contributors. This program is free software; you can redistribute it and/or modify diff --git a/src/network/lan.h b/src/network/lan.h index bd49c40f6..dddb7a1ff 100644 --- a/src/network/lan.h +++ b/src/network/lan.h @@ -1,5 +1,5 @@ /* -Minetest +Luanti Copyright (C) 2024 proller and contributors. This program is free software; you can redistribute it and/or modify From 283159c5ff36eb6dae6d54d7330728c3a9fbd9fe Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 17:23:07 -0600 Subject: [PATCH 20/24] Readd Server proto --- src/network/lan.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index c2a399ffe..d1abbef9f 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -69,6 +69,7 @@ typedef int socket_t; const char* adv_multicast_addr = "224.1.1.1"; const static unsigned short int adv_port = 29998; +const char* proto = "Luanti"; static std::string ask_str; bool use_ipv6 = true; @@ -84,6 +85,7 @@ void lan_adv::ask() if (ask_str.empty()) { Json::Value j; j["cmd"] = "ask"; + j["proto"] = proto; ask_str = fastWriteJson(j); } @@ -258,6 +260,7 @@ void *lan_adv::run() server["port"] = server_port; server["clients"] = clients_num.load(); server["clients_max"] = g_settings->getU16("max_users"); + server["proto"] = proto; send_string(fastWriteJson(server)); } @@ -280,7 +283,7 @@ void *lan_adv::run() if (server_port) { if (p["cmd"] == "ask" && limiter[addr_str] < now) { (clients_num.load() ? infostream : actionstream) - << "lan: want play " << addr_str << std::endl; + << "lan: want play " << addr_str << " " << p["proto"] << std::endl; server["clients"] = clients_num.load(); answer_str = fastWriteJson(server); @@ -292,7 +295,7 @@ void *lan_adv::run() } } else { if (p["cmd"] == "ask") { - actionstream << "lan: want play " << addr_str << std::endl; + actionstream << "lan: want play " << addr_str << " " << p["proto"] << std::endl; } if (p["port"].isInt()) { p["address"] = addr_str; @@ -302,7 +305,7 @@ void *lan_adv::run() //infostream << "server shutdown " << key << "\n"; collected.erase(key); fresh = true; - } else { + } else if (p["proto"] == proto) { if (!collected.count(key)) actionstream << "lan server start " << key << "\n"; collected.insert_or_assign(key, p); From 8ca5d145160226e6b5e75ec20485d60489f6e4cf Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 18:02:17 -0600 Subject: [PATCH 21/24] Fix Duplicate Servers in Server List --- src/network/lan.cpp | 72 ++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index d1abbef9f..9b3f32762 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -69,7 +69,7 @@ typedef int socket_t; const char* adv_multicast_addr = "224.1.1.1"; const static unsigned short int adv_port = 29998; -const char* proto = "Luanti"; +const std::string proto = "Luanti"; static std::string ask_str; bool use_ipv6 = true; @@ -94,7 +94,7 @@ void lan_adv::ask() void lan_adv::send_string(const std::string &str) { - if (g_settings->getBool("enable_ipv6")) { + if (g_settings->getBool("ipv6_server")) { std::vector scopes; // todo: windows and android @@ -150,36 +150,60 @@ void lan_adv::send_string(const std::string &str) socket_send.Send(Address(addr), str.c_str(), str.size()); } } catch (const std::exception &e) { - verbosestream << "udp broadcast send over ipv6 fail " << e.what() << "\n"; + verbosestream << "udp multicast send over ipv6 fail [" << e.what() << "]\n" << "Trying ipv4.\n"; + try { + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(adv_port); + UDPSocket socket_send(false); + + inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr)); + + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&mreq, sizeof(mreq)); + + //int set_option_on = 2; + //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL, + // (const char *)&set_option_on, sizeof(set_option_on)); + + socket_send.Send(Address(addr), str.c_str(), str.size()); + } catch (const std::exception &e) { + verbosestream << "udp mulitcast send over ipv4 fail too. " << e.what() << "\n"; + } } } freeaddrinfo(result); } - } + } else { + try { + sockaddr_in addr = {}; + addr.sin_family = AF_INET; + addr.sin_port = htons(adv_port); + UDPSocket socket_send(false); - try { - sockaddr_in addr = {}; - addr.sin_family = AF_INET; - addr.sin_port = htons(adv_port); - UDPSocket socket_send(false); + inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr)); - inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr)); + struct ip_mreq mreq; - struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); - mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); + setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&mreq, sizeof(mreq)); - setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char *)&mreq, sizeof(mreq)); + //int set_option_on = 2; + //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL, + // (const char *)&set_option_on, sizeof(set_option_on)); - //int set_option_on = 2; - //setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL, - // (const char *)&set_option_on, sizeof(set_option_on)); - - socket_send.Send(Address(addr), str.c_str(), str.size()); - } catch (const std::exception &e) { - verbosestream << "udp broadcast send over ipv4 fail " << e.what() << "\n"; + socket_send.Send(Address(addr), str.c_str(), str.size()); + } catch (const std::exception &e) { + verbosestream << "udp mulitcast send over ipv4 fail " << e.what() << "\n"; + } } } @@ -195,7 +219,7 @@ void *lan_adv::run() BEGIN_DEBUG_EXCEPTION_HANDLER; setName("lan_adv " + (server_port ? std::string("server") : std::string("client"))); - UDPSocket socket_recv(g_settings->getBool("enable_ipv6")); + UDPSocket socket_recv(g_settings->getBool("ipv6_server")); int set_option_off = 0, set_option_on = 1; setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEADDR, @@ -215,7 +239,7 @@ void *lan_adv::run() (const char *)&set_option_off, sizeof(set_option_off)); socket_recv.setTimeoutMs(200); - if (g_settings->getBool("enable_ipv6")) { + if (g_settings->getBool("ipv6_server")) { try { socket_recv.Bind(Address(in6addr_any, adv_port)); } catch (const std::exception &e) { From 1437b0aa79e84094930d50f081f2c319061e57e8 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Thu, 2 Jan 2025 18:22:46 -0600 Subject: [PATCH 22/24] proto Luatit -> luanti --- src/network/lan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/lan.cpp b/src/network/lan.cpp index 9b3f32762..1dd37d2d8 100644 --- a/src/network/lan.cpp +++ b/src/network/lan.cpp @@ -69,7 +69,7 @@ typedef int socket_t; const char* adv_multicast_addr = "224.1.1.1"; const static unsigned short int adv_port = 29998; -const std::string proto = "Luanti"; +const std::string proto = "lanti"; static std::string ask_str; bool use_ipv6 = true; From 665a02751b6d803fcf4fa2006b8ab792ba94a1c7 Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Mon, 26 May 2025 12:48:31 -0500 Subject: [PATCH 23/24] Fix 5.13 errors --- src/script/lua_api/l_mainmenu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index a6ad18c89..508bc9dc5 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1130,8 +1130,8 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(share_file); API_FCT(do_async_callback); API_FCT(ask_lan_servers); - API_FCT(get_lan_servers); - + API_FCT(get_lan_servers); + lua_pushboolean(L, g_first_run); lua_setfield(L, top, "is_first_run"); } @@ -1162,6 +1162,6 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(get_max_supp_proto); API_FCT(get_formspec_version); API_FCT(get_language); - API_FCT(gettext); API_FCT(get_lan_servers); API_FCT(ask_lan_servers); +} From 929f9f27363cf9b45c231c710eae7d951936254b Mon Sep 17 00:00:00 2001 From: DustyBagel Date: Mon, 26 May 2025 12:54:59 -0500 Subject: [PATCH 24/24] Fix Failed WhiteSpace CHecks #1 --- src/script/lua_api/l_mainmenu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 508bc9dc5..3b01f6614 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -1130,8 +1130,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(share_file); API_FCT(do_async_callback); API_FCT(ask_lan_servers); - API_FCT(get_lan_servers); - + API_FCT(get_lan_servers); lua_pushboolean(L, g_first_run); lua_setfield(L, top, "is_first_run"); }