Browse Source

Refactor RDNS resolution; update Jupiter; bug fixes

master
Jessica James 3 years ago
parent
commit
c2257f29f5
  1. 2
      baseline/Configs/RenX.Commands.ini
  2. 40
      src/Bot/src/Main.cpp
  3. 2
      src/Jupiter
  4. 5
      src/Plugins/RenX/RenX.Commands/RenX_Commands.cpp
  5. 4
      src/Plugins/RenX/RenX.Core/RenX_BanDatabase.cpp
  6. 26
      src/Plugins/RenX/RenX.Core/RenX_PlayerInfo.h
  7. 54
      src/Plugins/RenX/RenX.Core/RenX_Server.cpp
  8. 16
      src/Plugins/RenX/RenX.Core/RenX_Tags.cpp

2
baseline/Configs/RenX.Commands.ini

@ -2,7 +2,7 @@
; ;
; DefaultTBanTime=Integer (Default: 1d; 1 day) ; DefaultTBanTime=Integer (Default: 1d; 1 day)
; MaxTBanTime=Integer (Default: 1w; 1 week) ; MaxTBanTime=Integer (Default: 1w; 1 week)
; PlayerInfoFormat=String (Default: 03[Player Info]{TCOLOR} Name: {RNAME} - ID: {ID} - Team: {TEAML} - Vehicle Kills: {VEHICLEKILLS} - Building Kills {BUILDINGKILLS} - Kills {KILLS} - Deaths: {DEATHS} - KDR: {KDR} - Access: {ACCESS}") ; PlayerInfoFormat=String (Default: 03[Player Info]{TCOLOR} {RNAME} - ID: {ID} - Team: {TEAML} - Vehicle Kills: {VEHICLEKILLS} - Building Kills {BUILDINGKILLS} - Kills {KILLS} - Deaths: {DEATHS} - KDR: {KDR} - Access: {ACCESS}")
; AdminPlayerInfoFormat=String (Default: PlayerInfoFormat - IP: {IP} - Steam ID: {STEAM}) ; AdminPlayerInfoFormat=String (Default: PlayerInfoFormat - IP: {IP} - Steam ID: {STEAM})
; BuildingInfoFormat=String (Default: {BCOLOR} {BNAME} - 07{BHP}%) ; BuildingInfoFormat=String (Default: {BCOLOR} {BNAME} - 07{BHP}%)
; StaffTitle=String (Default: Moderator) ; StaffTitle=String (Default: Moderator)

40
src/Bot/src/Main.cpp

@ -24,6 +24,7 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include "jessilib/unicode.hpp" #include "jessilib/unicode.hpp"
#include "jessilib/app_parameters.hpp"
#include "Jupiter/Functions.h" #include "Jupiter/Functions.h"
#include "Jupiter/INIConfig.h" #include "Jupiter/INIConfig.h"
#include "Jupiter/Socket.h" #include "Jupiter/Socket.h"
@ -39,6 +40,7 @@
#endif // _WIN32 #endif // _WIN32
using namespace Jupiter::literals; using namespace Jupiter::literals;
using namespace std::literals;
Jupiter::INIConfig o_config; Jupiter::INIConfig o_config;
Jupiter::Config *Jupiter::g_config = &o_config; Jupiter::Config *Jupiter::g_config = &o_config;
@ -163,11 +165,10 @@ void reinitialize_plugins() {
} }
} }
int main(int argc, const char **args) { int main(int argc, char* argv[]) {
atexit(onExit); atexit(onExit);
std::set_terminate(onTerminate); std::set_terminate(onTerminate);
std::thread inputThread(inputLoop); std::thread inputThread(inputLoop);
Jupiter::ReferenceString plugins_directory, configs_directory;
#if defined SIGPIPE #if defined SIGPIPE
std::signal(SIGPIPE, SIG_IGN); std::signal(SIGPIPE, SIG_IGN);
@ -180,33 +181,24 @@ int main(int argc, const char **args) {
#endif // _WIN32 #endif // _WIN32
srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count())); srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
puts(Jupiter::copyright); std::cout << Jupiter::copyright << std::endl;
const char *configFileName = "Config.ini";
jessilib::app_parameters parameters{ argc, argv };
for (int i = 1; i < argc; i++) { if (parameters.has_switch("help"sv)) {
std::string_view arg_view = args[i]; std::cout << "Help coming soon, to a theatre near you!" << std::endl;
if (jessilib::equalsi("-help"_jrs, arg_view)) { return 0;
puts("Help coming soon, to a theatre near you!");
return 0;
}
else if (jessilib::equalsi("-config"_jrs, arg_view) && ++i < argc)
configFileName = args[i];
else if (jessilib::equalsi("-pluginsdir"_jrs, arg_view) && ++i < argc)
plugins_directory = arg_view;
else if (jessilib::equalsi("-configsdir"_jrs, arg_view) && ++i < argc)
configs_directory = arg_view;
else if (jessilib::equalsi("-configFormat"_jrs, arg_view) && ++i < argc)
puts("Feature not yet supported!");
else
printf("Warning: Unknown command line argument \"%s\" specified. Ignoring...", args[i]);
} }
std::string_view configFileName = parameters.get_value("config", "Config.ini"sv);
std::string_view plugins_directory = parameters.get_value("pluginsdir"sv);
std::string_view configs_directory = parameters.get_value("configsdir"sv);
std::chrono::steady_clock::time_point load_start = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point load_start = std::chrono::steady_clock::now();
puts("Loading config file..."); std::cout << "Loading config file..." << std::endl;
if (!o_config.read(configFileName)) { if (!o_config.read(configFileName)) {
puts("Unable to read config file. Closing..."); std::cout << "Unable to read config file. Closing..." << std::endl;
exit(0); return 1;
} }
double time_taken = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - load_start).count()) / 1000.0; double time_taken = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - load_start).count()) / 1000.0;

2
src/Jupiter

@ -1 +1 @@
Subproject commit 6b693b96a9f77d1ec49e11d991d9c5a75965f4c4 Subproject commit e4dc793c42ab7bbd1ca896d1c10d9f63244011b6

5
src/Plugins/RenX/RenX.Commands/RenX_Commands.cpp

@ -79,9 +79,8 @@ bool RenX_CommandsPlugin::initialize() {
auto max_tban_time = this->config.get("MaxTBanTime"_jrs, "1w"_jrs); auto max_tban_time = this->config.get("MaxTBanTime"_jrs, "1w"_jrs);
m_defaultTempBanTime = jessilib::duration_from_string(default_tban_time.data(), default_tban_time.data() + default_tban_time.size()).duration; m_defaultTempBanTime = jessilib::duration_from_string(default_tban_time.data(), default_tban_time.data() + default_tban_time.size()).duration;
m_maxTempBanTime = std::max(jessilib::duration_from_string(max_tban_time.data(), max_tban_time.data() + max_tban_time.size()).duration, m_defaultTempBanTime); m_maxTempBanTime = std::max(jessilib::duration_from_string(max_tban_time.data(), max_tban_time.data() + max_tban_time.size()).duration, m_defaultTempBanTime);
m_playerInfoFormat = this->config.get("PlayerInfoFormat"_jrs, IRCCOLOR "03[Player Info]" IRCCOLOR "{TCOLOR} Name: " IRCBOLD "{RNAME}" IRCBOLD " - ID: {ID} - Team: " IRCBOLD "{TEAML}" IRCBOLD " - Vehicle Kills: {VEHICLEKILLS} - Building Kills {BUILDINGKILLS} - Kills {KILLS} - Deaths: {DEATHS} - KDR: {KDR} - Access: {ACCESS}"_jrs); m_playerInfoFormat = this->config.get("PlayerInfoFormat"_jrs, IRCCOLOR "03[Player Info]" IRCCOLOR "{TCOLOR} " IRCBOLD "{RNAME}" IRCBOLD " - ID: {ID} - Team: " IRCBOLD "{TEAML}" IRCBOLD " - Vehicle Kills: {VEHICLEKILLS} - Building Kills {BUILDINGKILLS} - Kills {KILLS} - Deaths: {DEATHS} - KDR: {KDR} - Access: {ACCESS}"_jrs);
m_adminPlayerInfoFormat = this->config.get("AdminPlayerInfoFormat"_jrs, Jupiter::StringS::Format("%.*s - IP: " IRCBOLD "{IP}" IRCBOLD " - HWID: " IRCBOLD "{HWID}" IRCBOLD " - RDNS: " IRCBOLD "{RDNS}" IRCBOLD " - Steam ID: " IRCBOLD "{STEAM}", m_playerInfoFormat.size(), m_adminPlayerInfoFormat = this->config.get("AdminPlayerInfoFormat"_jrs, m_playerInfoFormat + " - IP: " IRCBOLD "{IP}" IRCBOLD " - HWID: " IRCBOLD "{HWID}" IRCBOLD " - RDNS: " IRCBOLD "{RDNS}" IRCBOLD " - Steam ID: " IRCBOLD "{STEAM}");
m_playerInfoFormat.data()));
m_buildingInfoFormat = this->config.get("BuildingInfoFormat"_jrs, ""s IRCCOLOR + RenX::tags->buildingTeamColorTag + RenX::tags->buildingNameTag + IRCCOLOR " - " IRCCOLOR "07"_jrs + RenX::tags->buildingHealthPercentageTag + "%"_jrs); m_buildingInfoFormat = this->config.get("BuildingInfoFormat"_jrs, ""s IRCCOLOR + RenX::tags->buildingTeamColorTag + RenX::tags->buildingNameTag + IRCCOLOR " - " IRCCOLOR "07"_jrs + RenX::tags->buildingHealthPercentageTag + "%"_jrs);
m_staffTitle = this->config.get("StaffTitle"_jrs, "Moderator"_jrs); m_staffTitle = this->config.get("StaffTitle"_jrs, "Moderator"_jrs);

4
src/Plugins/RenX/RenX.Core/RenX_BanDatabase.cpp

@ -171,9 +171,7 @@ void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo &player
if (player.hwid.find_first_not_of('0') != std::string::npos) { if (player.hwid.find_first_not_of('0') != std::string::npos) {
entry->hwid = player.hwid; entry->hwid = player.hwid;
} }
if (player.rdns_thread.joinable()) entry->rdns = player.get_rdns();
player.rdns_thread.join();
entry->rdns = player.rdns;
entry->name = player.name; entry->name = player.name;
entry->banner = banner; entry->banner = banner;
entry->reason = reason; entry->reason = reason;

26
src/Plugins/RenX/RenX.Core/RenX_PlayerInfo.h

@ -55,9 +55,7 @@ namespace RenX
std::string uuid; std::string uuid;
Jupiter::StringS character; Jupiter::StringS character;
Jupiter::StringS vehicle; Jupiter::StringS vehicle;
std::string rdns;
std::string hwid; std::string hwid;
std::mutex rdns_mutex;
uint64_t steamid = 0; uint64_t steamid = 0;
uint32_t ip32 = 0; uint32_t ip32 = 0;
uint16_t ban_flags = 0; uint16_t ban_flags = 0;
@ -66,7 +64,6 @@ namespace RenX
int id = 0; int id = 0;
bool isBot = false; bool isBot = false;
bool is_dev = false; bool is_dev = false;
bool rdns_resolved = false;
unsigned short ping = 0; unsigned short ping = 0;
double score = 0.0f; double score = 0.0f;
double credits = 0.0f; double credits = 0.0f;
@ -88,12 +85,31 @@ namespace RenX
unsigned int captures = 0; unsigned int captures = 0;
unsigned int steals = 0; unsigned int steals = 0;
unsigned int stolen = 0; unsigned int stolen = 0;
// Lock-free getter -- never access m_rdns until it's been set by RDNS thread
std::string_view get_rdns() const {
if (m_rdns_ptr.use_count() != 1
|| m_rdns_ptr == nullptr) {
return {};
}
// In theory if get_rdns() were ever called at the same time as start_resolve_rdns(), on separate threads,
// then there would be a race condition here causing undefined behavior. However, we only interact with
// players on a single thread, and even beyond that, we only call start_resolve_rdns() immediately after
// constructing PlayerInfo. Therefore, this is safe
return *m_rdns_ptr;
}
static void resolve_rdns(std::string in_ip, std::shared_ptr<std::string> out_rdns);
void start_resolve_rdns();
bool rdns_pending = false;
mutable Jupiter::StringS gamePrefix; mutable Jupiter::StringS gamePrefix;
mutable Jupiter::StringS formatNamePrefix; mutable Jupiter::StringS formatNamePrefix;
mutable std::thread rdns_thread;
mutable int access = 0; mutable int access = 0;
mutable Jupiter::Config varData; mutable Jupiter::Config varData; // TODO: use jessilib::object instead
private:
std::shared_ptr<std::string> m_rdns_ptr; // Needs synchronization across threads
}; };
static std::string_view rdns_pending{ "RDNS_PENDING" }; static std::string_view rdns_pending{ "RDNS_PENDING" };

54
src/Plugins/RenX/RenX.Core/RenX_Server.cpp

@ -65,24 +65,23 @@ int RenX::Server::think() {
else { else {
auto cycle_player_rdns = [this]() { // Cycles through any pending RDNS resolutions, and fires events as necessary. auto cycle_player_rdns = [this]() { // Cycles through any pending RDNS resolutions, and fires events as necessary.
if (m_player_rdns_resolutions_pending != 0) { if (m_player_rdns_resolutions_pending != 0) {
for (auto node = this->players.begin(); node != this->players.end(); ++node) { for (auto& player : players) {
if (node->rdns_thread.joinable() && node->rdns_mutex.try_lock()) { // RDNS event hasn't fired AND RDNS value has been resolved if (player.rdns_pending && !player.get_rdns().empty()) { // RDNS event hasn't fired AND RDNS value has been resolved
node->rdns_mutex.unlock(); player.rdns_pending = false;
node->rdns_thread.join();
--m_player_rdns_resolutions_pending; --m_player_rdns_resolutions_pending;
// Check for bans // Check for bans
banCheck(*node); banCheck(player);
// Fire RDNS resolved event // Fire RDNS resolved event
for (const auto& plugin : RenX::getCore()->getPlugins()) { for (const auto& plugin : RenX::getCore()->getPlugins()) {
plugin->RenX_OnPlayerRDNS(*this, *node); plugin->RenX_OnPlayerRDNS(*this, player);
} }
// Fire player indentified event if ready // Fire player indentified event if ready
if (!node->hwid.empty()) { if (!player.hwid.empty()) {
for (auto plugin : RenX::getCore()->getPlugins()) { for (auto plugin : RenX::getCore()->getPlugins()) {
plugin->RenX_OnPlayerIdentify(*this, *node); plugin->RenX_OnPlayerIdentify(*this, player);
} }
} }
@ -555,7 +554,7 @@ void RenX::Server::banCheck(RenX::PlayerInfo &player) {
if ((m_localSteamBan && entry->steamid != 0 && entry->steamid == player.steamid) if ((m_localSteamBan && entry->steamid != 0 && entry->steamid == player.steamid)
|| (m_localIPBan && entry->ip != 0 && (entry->ip & netmask) == (player.ip32 & netmask)) || (m_localIPBan && entry->ip != 0 && (entry->ip & netmask) == (player.ip32 & netmask))
|| (m_localHWIDBan && !entry->hwid.empty() && entry->hwid == player.hwid) || (m_localHWIDBan && !entry->hwid.empty() && entry->hwid == player.hwid)
|| (m_localRDNSBan && !entry->rdns.empty() && entry->is_rdns_ban() && !player.rdns_thread.joinable() && player.rdns.find(entry->rdns) != std::string::npos) || (m_localRDNSBan && !entry->rdns.empty() && entry->is_rdns_ban() && player.get_rdns().find(entry->rdns) != std::string::npos)
|| (m_localNameBan && !entry->name.empty() && jessilib::equalsi(entry->name, player.name))) { || (m_localNameBan && !entry->name.empty() && jessilib::equalsi(entry->name, player.name))) {
player.ban_flags |= entry->flags; player.ban_flags |= entry->flags;
if (entry->is_type_game()) if (entry->is_type_game())
@ -735,9 +734,8 @@ bool RenX::Server::removePlayer(int id) {
--m_bot_count; --m_bot_count;
} }
if (node->rdns_thread.joinable()) { // Close the RDNS thread, if one exists if (node->rdns_pending) {
--m_player_rdns_resolutions_pending; --m_player_rdns_resolutions_pending;
node->rdns_thread.join();
} }
this->players.erase(node); this->players.erase(node);
@ -1302,14 +1300,17 @@ void RenX::Server::sendLogChan(std::string_view msg) const {
} }
} }
void resolve_rdns(RenX::PlayerInfo *player) { void RenX::PlayerInfo::resolve_rdns(std::string in_ip, std::shared_ptr<std::string> out_rdns) {
player->rdns_mutex.lock(); *out_rdns = Jupiter::Socket::resolveHostname(in_ip.c_str(), 0);
}
void RenX::PlayerInfo::start_resolve_rdns() {
rdns_pending = true;
// TODO: don't do this std::string player_ip = ip;
char *resolved = Jupiter::Socket::resolveHostname_alloc(static_cast<std::string>(player->ip).c_str(), 0); auto rdns_string = std::make_shared<std::string>();
player->rdns = resolved; m_rdns_ptr = rdns_string;
delete[] resolved; std::thread(resolve_rdns, ip, std::move(rdns_string)).detach();
player->rdns_mutex.unlock();
} }
struct parsed_player_token { struct parsed_player_token {
@ -1519,7 +1520,7 @@ void RenX::Server::processLine(std::string_view line) {
// RDNS // RDNS
if (resolvesRDNS() && player->ip32 != 0) if (resolvesRDNS() && player->ip32 != 0)
{ {
player->rdns_thread = std::thread(resolve_rdns, player); player->start_resolve_rdns();
++m_player_rdns_resolutions_pending; ++m_player_rdns_resolutions_pending;
} }
@ -1555,7 +1556,7 @@ void RenX::Server::processLine(std::string_view line) {
player->ip32 = Jupiter::Socket::pton4(static_cast<std::string>(player->ip).c_str()); player->ip32 = Jupiter::Socket::pton4(static_cast<std::string>(player->ip).c_str());
if (resolvesRDNS()) if (resolvesRDNS())
{ {
player->rdns_thread = std::thread(resolve_rdns, player); player->start_resolve_rdns();
++m_player_rdns_resolutions_pending; ++m_player_rdns_resolutions_pending;
} }
recalcUUID = true; recalcUUID = true;
@ -2847,8 +2848,7 @@ void RenX::Server::processLine(std::string_view line) {
} }
} }
} }
else if (subHeader == "HWID;"sv) else if (subHeader == "HWID;"sv) {
{
// ["player" |] Player | "hwid" | HWID // ["player" |] Player | "hwid" | HWID
size_t offset = 0; size_t offset = 0;
if (getToken(2) == "player"sv) if (getToken(2) == "player"sv)
@ -2865,7 +2865,7 @@ void RenX::Server::processLine(std::string_view line) {
plugin->RenX_OnHWID(*this, *player); plugin->RenX_OnHWID(*this, *player);
} }
if (!player->rdns.empty()) { if (!player->rdns_pending) {
for (const auto& plugin : xPlugins) { for (const auto& plugin : xPlugins) {
plugin->RenX_OnPlayerIdentify(*this, *player); plugin->RenX_OnPlayerIdentify(*this, *player);
} }
@ -3654,14 +3654,10 @@ void RenX::Server::wipePlayers() {
for (const auto& plugin : RenX::getCore()->getPlugins()) { for (const auto& plugin : RenX::getCore()->getPlugins()) {
plugin->RenX_OnPlayerDelete(*this, this->players.front()); plugin->RenX_OnPlayerDelete(*this, this->players.front());
} }
if (this->players.front().rdns_thread.joinable()) { // Close the RDNS thread, if one exists
--m_player_rdns_resolutions_pending;
this->players.front().rdns_thread.join();
}
this->players.pop_front(); this->players.pop_front();
} }
m_player_rdns_resolutions_pending = 0;
} }
void RenX::Server::startPing() { void RenX::Server::startPing() {

16
src/Plugins/RenX/RenX.Core/RenX_Tags.cpp

@ -477,13 +477,11 @@ void TagsImp::processTags(std::string& msg, const RenX::Server *server, const Re
PROCESS_TAG(this->INTERNAL_RAW_NAME_TAG, player->name); PROCESS_TAG(this->INTERNAL_RAW_NAME_TAG, player->name);
PROCESS_TAG(this->INTERNAL_IP_TAG, player->ip); PROCESS_TAG(this->INTERNAL_IP_TAG, player->ip);
PROCESS_TAG(this->INTERNAL_HWID_TAG, player->hwid); PROCESS_TAG(this->INTERNAL_HWID_TAG, player->hwid);
if (player->rdns_thread.joinable()) if (player->rdns_pending) {
{
PROCESS_TAG(this->INTERNAL_RDNS_TAG, RenX::rdns_pending); PROCESS_TAG(this->INTERNAL_RDNS_TAG, RenX::rdns_pending);
} }
else else {
{ PROCESS_TAG(this->INTERNAL_RDNS_TAG, player->get_rdns());
PROCESS_TAG(this->INTERNAL_RDNS_TAG, player->rdns);
} }
PROCESS_TAG(this->INTERNAL_UUID_TAG, player->uuid); PROCESS_TAG(this->INTERNAL_UUID_TAG, player->uuid);
PROCESS_TAG(this->INTERNAL_ID_TAG, Jupiter::StringS::Format("%d", player->id)); PROCESS_TAG(this->INTERNAL_ID_TAG, Jupiter::StringS::Format("%d", player->id));
@ -523,13 +521,11 @@ void TagsImp::processTags(std::string& msg, const RenX::Server *server, const Re
PROCESS_TAG(this->INTERNAL_VICTIM_RAW_NAME_TAG, victim->name); PROCESS_TAG(this->INTERNAL_VICTIM_RAW_NAME_TAG, victim->name);
PROCESS_TAG(this->INTERNAL_VICTIM_IP_TAG, victim->ip); PROCESS_TAG(this->INTERNAL_VICTIM_IP_TAG, victim->ip);
PROCESS_TAG(this->INTERNAL_VICTIM_HWID_TAG, victim->hwid); PROCESS_TAG(this->INTERNAL_VICTIM_HWID_TAG, victim->hwid);
if (victim->rdns_thread.joinable()) if (victim->rdns_pending) {
{
PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, RenX::rdns_pending); PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, RenX::rdns_pending);
} }
else else {
{ PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, victim->get_rdns());
PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, victim->rdns);
} }
PROCESS_TAG(this->INTERNAL_VICTIM_UUID_TAG, victim->uuid); PROCESS_TAG(this->INTERNAL_VICTIM_UUID_TAG, victim->uuid);
PROCESS_TAG(this->INTERNAL_VICTIM_ID_TAG, Jupiter::StringS::Format("%d", victim->id)); PROCESS_TAG(this->INTERNAL_VICTIM_ID_TAG, Jupiter::StringS::Format("%d", victim->id));

Loading…
Cancel
Save