Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- 'develop'
- 'minor'
pull_request:
workflow_dispatch:

env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
Expand Down
10 changes: 10 additions & 0 deletions include/ArgsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class ArgsParser {

ArgsParser() = default;

/**
* Parse all arguments provided, if they have been register.
*/
void Parse(const std::vector<std::string_view>& ArgList);
// prints errors if any errors occurred, in that case also returns false
bool Verify();
Expand All @@ -48,8 +51,15 @@ class ArgsParser {
std::optional<std::string> GetValueOfArgument(const std::vector<std::string>& Names);

private:

/**
* Register an argument with a value.
*/
void ConsumeLongAssignment(const std::string& Arg);
void ConsumeLongFlag(const std::string& Arg);
/**
* return if the argument asked has been registered previously.
*/
bool IsRegistered(const std::string& Name);

struct Argument {
Expand Down
1 change: 1 addition & 0 deletions include/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct Settings {
General_Map,
General_AuthKey,
General_Private,
General_Ip,
General_Port,
General_MaxCars,
General_LogChat,
Expand Down
1 change: 0 additions & 1 deletion include/TServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class TServer final {

void InsertClient(const std::shared_ptr<TClient>& Ptr);
void RemoveClient(const std::weak_ptr<TClient>&);
// in Fn, return true to continue, return false to break
void ForEachClient(const std::function<bool(std::weak_ptr<TClient>)>& Fn);
size_t ClientCount() const;

Expand Down
2 changes: 1 addition & 1 deletion src/ArgsParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
void ArgsParser::Parse(const std::vector<std::string_view>& ArgList) {
for (const auto& Arg : ArgList) {
if (Arg.size() > 2 && Arg.substr(0, 2) == "--") {
// long arg
// Arg with value
if (Arg.find("=") != Arg.npos) {
ConsumeLongAssignment(std::string(Arg));
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/Http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <stdexcept>

using json = nlohmann::json;

struct Connection {
std::string host {};
int port {};
Expand All @@ -37,6 +38,7 @@ struct Connection {
: host(host)
, port(port) {};
};

constexpr uint8_t CONNECTION_AMOUNT = 10;
static thread_local uint8_t write_index = 0;
static thread_local std::array<Connection, CONNECTION_AMOUNT> connections;
Expand All @@ -62,7 +64,7 @@ static thread_local std::array<std::shared_ptr<httplib::SSLClient>, CONNECTION_A
std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) {
std::shared_ptr<httplib::SSLClient> client = getClient({ host, port });
client->enable_server_certificate_verification(false);
client->set_address_family(AF_INET);
client->set_address_family(AF_UNSPEC);
auto res = client->Get(target.c_str());
if (res) {
if (status) {
Expand All @@ -79,7 +81,7 @@ std::string Http::POST(const std::string& host, int port, const std::string& tar
client->set_read_timeout(std::chrono::seconds(10));
beammp_assert(client->is_valid());
client->enable_server_certificate_verification(false);
client->set_address_family(AF_INET);
client->set_address_family(AF_UNSPEC);
auto res = client->Post(target.c_str(), headers, body.c_str(), body.size(), ContentType.c_str());
if (res) {
if (status) {
Expand Down
2 changes: 2 additions & 0 deletions src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Settings::Settings() {
{ General_Map, std::string("/levels/gridmap_v2/info.json") },
{ General_AuthKey, std::string("") },
{ General_Private, true },
{ General_Ip, "0.0.0.0" },
{ General_Port, 30814 },
{ General_MaxCars, 1 },
{ General_LogChat, true },
Expand All @@ -48,6 +49,7 @@ Settings::Settings() {
{ { "General", "Map" }, { General_Map, READ_WRITE } },
{ { "General", "AuthKey" }, { General_AuthKey, NO_ACCESS } },
{ { "General", "Private" }, { General_Private, READ_ONLY } },
{ { "General", "Ip" }, { General_Ip, READ_ONLY } },
{ { "General", "Port" }, { General_Port, READ_ONLY } },
{ { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } },
{ { "General", "LogChat" }, { General_LogChat, READ_ONLY } },
Expand Down
5 changes: 5 additions & 0 deletions src/TConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ static constexpr std::string_view StrDebug = "Debug";
static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG";
static constexpr std::string_view StrPrivate = "Private";
static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE";
static constexpr std::string_view StrIp = "Ip";
static constexpr std::string_view EnvStrIp = "BEAMMP_IP";
static constexpr std::string_view StrPort = "Port";
static constexpr std::string_view EnvStrPort = "BEAMMP_PORT";
static constexpr std::string_view StrMaxCars = "MaxCars";
Expand Down Expand Up @@ -134,6 +136,7 @@ void TConfig::FlushToFile() {
data["General"][StrPrivate.data()] = Application::Settings.getAsBool(Settings::Key::General_Private);
data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests);
SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests");
data["General"][StrIp.data()] = Application::Settings.getAsString(Settings::Key::General_Ip);
data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port);
data["General"][StrName.data()] = Application::Settings.getAsString(Settings::Key::General_Name);
SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation.");
Expand Down Expand Up @@ -248,6 +251,7 @@ void TConfig::ParseFromFile(std::string_view name) {
// Read into new Settings Singleton
TryReadValue(data, "General", StrDebug, EnvStrDebug, Settings::Key::General_Debug);
TryReadValue(data, "General", StrPrivate, EnvStrPrivate, Settings::Key::General_Private);
TryReadValue(data, "General", StrIp, EnvStrIp, Settings::Key::General_Ip);
TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port);
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars);
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers);
Expand Down Expand Up @@ -299,6 +303,7 @@ void TConfig::PrintDebug() {
}
beammp_debug(std::string(StrDebug) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Debug) ? "true" : "false"));
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false"));
beammp_debug(std::string(StrIp) + ": " + Application::Settings.getAsString(Settings::Key::General_Ip));
beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)));
beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxCars)));
beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)));
Expand Down
1 change: 1 addition & 0 deletions src/THeartbeatThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ std::string THeartbeatThread::GenerateCall() {
Ret << "uuid=" << Application::Settings.getAsString(Settings::Key::General_AuthKey)
<< "&players=" << mServer.ClientCount()
<< "&maxplayers=" << Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)
<< "&ip=" << Application::Settings.getAsString(Settings::Key::General_Ip) // TODO Add on the website the usage of this info
<< "&port=" << Application::Settings.getAsInt(Settings::Key::General_Port)
<< "&map=" << Application::Settings.getAsString(Settings::Key::General_Map)
<< "&private=" << (Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false")
Expand Down
38 changes: 30 additions & 8 deletions src/TNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,16 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R

void TNetwork::UDPServerMain() {
RegisterThread("UDPServer");
ip::udp::endpoint UdpListenEndpoint(ip::address::from_string("0.0.0.0"), Application::Settings.getAsInt(Settings::Key::General_Port));

boost::system::error_code ec;

auto add = ip::make_address(Application::Settings.getAsString(Settings::Key::General_Ip), ec);
if (ec) {
beammp_errorf("Invalid address: {}", ec.message());
return;
}

ip::udp::endpoint UdpListenEndpoint(add, Application::Settings.getAsInt(Settings::Key::General_Port));
mUDPSock.open(UdpListenEndpoint.protocol(), ec);
if (ec) {
beammp_error("open() failed: " + ec.message());
Expand All @@ -96,7 +104,8 @@ void TNetwork::UDPServerMain() {
Application::GracefullyShutdown();
}
Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good);
beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)) + (" with a Max of ")
beammp_info(("Vehicle data network online on ") + Application::Settings.getAsString(Settings::Key::General_Ip)
+ " on port " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)) + (" with a Max of ")
+ std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) + (" Clients"));
while (!Application::IsShuttingDown()) {
try {
Expand Down Expand Up @@ -134,9 +143,16 @@ void TNetwork::UDPServerMain() {
void TNetwork::TCPServerMain() {
RegisterThread("TCPServer");

ip::tcp::endpoint ListenEp(ip::address::from_string("0.0.0.0"), Application::Settings.getAsInt(Settings::Key::General_Port));
ip::tcp::socket Listener(mServer.IoCtx());
boost::system::error_code ec;

auto add = ip::make_address(Application::Settings.getAsString(Settings::Key::General_Ip), ec);
if (ec) {
beammp_errorf("Invalid address: {}", ec.message());
return;
}
ip::tcp::endpoint ListenEp(add, Application::Settings.getAsInt(Settings::Key::General_Port));
ip::tcp::socket Listener(mServer.IoCtx());

Listener.open(ListenEp.protocol(), ec);
if (ec) {
beammp_errorf("Failed to open socket: {}", ec.message());
Expand Down Expand Up @@ -168,13 +184,19 @@ void TNetwork::TCPServerMain() {
break;
}
ip::tcp::endpoint ClientEp;
//Wait to a client
ip::tcp::socket ClientSocket = Acceptor.accept(ClientEp, ec);
if (ec) {
beammp_errorf("failed to accept: {}", ec.message());
if (ec == boost::asio::error::interrupted) {
continue;
}else
beammp_errorf("failed to accept: {}", ec.message());
} else {
TConnection Conn { std::move(ClientSocket), ClientEp };
std::thread ID(&TNetwork::Identify, this, std::move(Conn));
ID.detach(); // TODO: Add to a queue and attempt to join periodically
}
TConnection Conn { std::move(ClientSocket), ClientEp };
std::thread ID(&TNetwork::Identify, this, std::move(Conn));
ID.detach(); // TODO: Add to a queue and attempt to join periodically

} catch (const std::exception& e) {
beammp_error("fatal: " + std::string(e.what()));
}
Expand Down
24 changes: 23 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ static const std::string sCommandlineArguments = R"(
ARGUMENTS:
--help
Displays this help and exits.
--ip=<IPv4|IPv6>
Sets the server's ip to listen on.
Overrides ENV and ServerConfig value.
--port=1234
Sets the server's listening TCP and
UDP port. Overrides ENV and ServerConfig.
UDP port. Overrides ENV and ServerConfig value.
--config=/path/to/ServerConfig.toml
Absolute or relative path to the
Server Config file, including the
Expand Down Expand Up @@ -74,6 +77,7 @@ struct MainArguments {
int BeamMPServerMain(MainArguments Arguments);

int main(int argc, char** argv) {

MainArguments Args { argc, argv, {}, argv[0] };
Args.List.reserve(size_t(argc));
for (int i = 1; i < argc; ++i) {
Expand All @@ -96,6 +100,7 @@ int BeamMPServerMain(MainArguments Arguments) {
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE);
Parser.RegisterArgument({ "ip" }, ArgsParser::HAS_VALUE);
Parser.RegisterArgument({ "port" }, ArgsParser::HAS_VALUE);
Parser.RegisterArgument({ "working-directory" }, ArgsParser::HAS_VALUE);
Parser.Parse(Arguments.List);
Expand Down Expand Up @@ -142,6 +147,21 @@ int BeamMPServerMain(MainArguments Arguments) {
return 1;
}

// override default IP (0.0.0.0) if provided via arguments
if (Parser.FoundArgument({ "ip" })) {
auto ip = Parser.GetValueOfArgument({ "ip" });
if (ip.has_value()) {
const std::regex patternIPv4IPv6(R"(((^\h*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\h*(|/([0-9]|[1-2][0-9]|3[0-2]))$)|(^\h*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\h*(|/([0-9]|[0-9][0-9]|1[0-1][0-9]|12[0-8]))$)))");
if (std::regex_match(ip.value(), patternIPv4IPv6)) {
beammp_errorf("Custom ip requested via --ip is invalid: '{}'", ip.value());
return 1;
} else {
Application::Settings.set(Settings::Key::General_Ip, ip.value());
beammp_info("Custom ip requested via commandline arguments: " + ip.value());
}
}
}

// override port if provided via arguments
if (Parser.FoundArgument({ "port" })) {
auto Port = Parser.GetValueOfArgument({ "port" });
Expand Down Expand Up @@ -206,6 +226,8 @@ int BeamMPServerMain(MainArguments Arguments) {
"UpdateCheck" // Ignore as not to confuse users (non-vital system)
};



bool FullyStarted = false;
while (!Shutdown) {
if (!FullyStarted) {
Expand Down
3 changes: 2 additions & 1 deletion vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"openssl",
"rapidjson",
"sol2",
"toml11"
"toml11",
"lua"
]
}