Compare commits

...

57 Commits

Author SHA1 Message Date
Anonymous275
e0b7dd76fd Static server build 2021-01-07 23:45:17 +02:00
Anonymous275
fc4bc14ce5 Potential auth fix 2021-01-07 15:29:06 +02:00
Lion Kortlepel
61776d6a1b Client: inline trivial getters & setters 2021-01-02 03:19:51 +01:00
Lion Kortlepel
0f30706a0a Improve UDPRcvFromClient 2021-01-02 02:55:14 +01:00
Lion Kortlepel
cb92833bfd Fix useless strlen & substr 2021-01-02 02:42:39 +01:00
Lion Kortlepel
a21ca74c58 remove include 2021-01-02 02:39:18 +01:00
Lion Kortlepel
e2611e13e0 Console.cpp: Fix console history crashes and inconsistent behavior 2021-01-02 01:00:35 +01:00
Lion Kortlepel
5fb7c459c6 main.cpp: use c++ header naming scheme 2021-01-02 00:10:01 +01:00
Lion
d8e1d389bf Update README.md 2021-01-01 16:23:38 +01:00
Anonymous275
ae03b5f5ce Merge pull request #6 from BeamMP/license-file
Create LICENSE
2020-12-31 18:54:02 +02:00
Lion
2c6386013d Update README.md 2020-12-27 23:11:23 +01:00
Lion
3cb4c7cb67 Update README.md 2020-12-27 22:49:24 +01:00
Lion
229010647c Update README.md 2020-12-27 22:30:22 +01:00
Lion
03968f34b1 Update README.md 2020-12-27 22:28:15 +01:00
Lion Kortlepel
941287d22c remove debian build script again, rethinking this 2020-12-27 22:17:10 +01:00
Lion Kortlepel
8e4e0c0896 add debian build script for easier deployment 2020-12-27 22:13:24 +01:00
Lion Kortlepel
c5d1682d5e CMake: Change minimum required version to 3.13, due to it being the
default in debian stable which we officially will support now, and
changed "lua" to find_directories result in UNIX linking of libraries
2020-12-27 22:06:48 +01:00
Lion Kortlepel
04cf7ca092 suppress unused variables 2020-12-24 00:42:39 +01:00
Lion Kortlepel
639c94e0f2 fixed my own mistake again again 2020-12-24 00:01:09 +01:00
Lion Kortlepel
623437e864 fix not calling curl_global_init in release mode 2020-12-23 23:57:27 +01:00
Lion Kortlepel
fb420eac1b fix not memsetting in release mode (yikes) 2020-12-23 23:56:17 +01:00
Lion Kortlepel
0f33367f6b fixed what i broke 2020-12-23 23:52:51 +01:00
Lion Kortlepel
1a2c956d9e remove dead code in logger's SetThreadName 2020-12-23 23:45:28 +01:00
Lion Kortlepel
de859f4762 remove Pos < 0 check as Pos is unsigned and never < 0 (always true) 2020-12-23 23:45:28 +01:00
Lion Kortlepel
db152e09e9 reduce scope of some variables
reduce scope of R in Monitor

reduce scope of Temp in TCPSendRaw

reduce scope of Temp in TCPSend
2020-12-23 23:45:21 +01:00
Lion Kortlepel
561c0bb381 fix bug which caused kicking to be logged as normal leaving 2020-12-23 23:45:21 +01:00
Lion Kortlepel
f60a44f65f remove some unused variables
remove unused variable

remove unused variable
2020-12-23 23:45:12 +01:00
Lion Kortlepel
a944565fb9 reformat all 2020-12-23 23:34:30 +01:00
Lion Kortlepel
0f4c08c068 reformat all 2020-12-23 23:30:33 +01:00
Lion Kortlepel
f0ad3732f4 fix misplaced include 2020-12-23 23:29:45 +01:00
Anonymous275
4adfda64c1 Switched to msvc 2019 2020-12-24 00:16:40 +02:00
Anonymous275
306fbc5eb4 Cleaning headers 2020-12-23 23:56:43 +02:00
Lion
fac1b43b44 Create LICENSE
please read over this and make sure its solid enough
2020-12-23 21:51:51 +01:00
Anonymous275
b22a9566f9 Update README.md 2020-12-23 21:02:25 +02:00
Anonymous275
6f0c69904c Update README.md 2020-12-23 20:52:09 +02:00
Anonymous275
e049b1bbf4 Folder cleanup 2020-12-22 10:20:30 +02:00
Anonymous275
ef8f8645f7 Final Commit v1.20 2020-12-22 00:25:55 +02:00
Anonymous275
f94252d37b Update Sync.cpp 2020-12-20 16:04:15 +02:00
Anonymous275
8f042a3ee4 Update README.md 2020-12-20 15:29:46 +02:00
Anonymous275
435c397d02 Small edit 2020-12-20 15:14:23 +02:00
Anonymous275
97d8f9506e more cleanup 2020-12-20 14:11:29 +02:00
Anonymous275
2e7f2cc6bd Support of 1Gps+ internet 2020-12-19 01:15:52 +02:00
Anonymous275
19b7f7f579 new auth system + major optimization 2020-12-16 01:36:35 +02:00
Anonymous275
6a29384b5c cleaned comment 2020-11-27 10:34:13 +02:00
Anonymous275
69da77937d UDP Cleanup 2020-11-25 20:26:47 +02:00
Lion Kortlepel
5cf97850d7 add nobuiltin flag for gcc 2020-11-24 01:28:35 +01:00
Anonymous275
ad844db7fe v1.13 2020-11-21 00:29:30 +02:00
Lion Kortlepel
6a8d097dc5 fixup 2020-11-17 23:25:59 +01:00
Lion Kortlepel
e2a45601b3 possibly fix recurring backend timeout 2020-11-17 23:21:45 +01:00
Lion Kortlepel
a78f65b274 fix getch spin 2020-11-17 23:21:45 +01:00
Anonymous275
04de729d7c console setup errors will no longer deny a server startup 2020-11-17 08:28:02 +02:00
Anonymous275
667a22b0f8 Fixed lua command not registered for console 2020-11-16 21:09:13 +02:00
Lion Kortlepel
e12b7da27f lua unique_ptr to shared_ptr 2020-11-16 16:48:00 +01:00
Lion Kortlepel
450f6d7139 rearrange cmakelists 2020-11-16 15:39:23 +01:00
Anonymous275
086bcb5ecc Server 1.1 2020-11-16 02:45:32 +02:00
Anonymous275
ac05cb5d0e Added vehicle 't' case 2020-11-15 17:11:16 +02:00
Anonymous275
92c44b19c5 HotSwap linux fix 2020-11-14 23:26:42 +02:00
38 changed files with 852 additions and 1207 deletions

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/BeamNG-MP-Server.iml" filepath="$PROJECT_DIR$/.idea/BeamNG-MP-Server.iml" />
</modules>
</component>
</project>

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.13)
project(Server)
set(CMAKE_CXX_STANDARD 17)
@@ -7,31 +7,37 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s -fno-builtin")
elseif (WIN32)
# This might cause issues with old windows headers, but it's worth the trouble to keep the code
# completely cross platform. For fixes to common issues arising from /permissive- visit:
# https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /permissive-")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /permissive-")
message(STATUS "MSVC -> forcing use of statically-linked runtime.")
STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
#-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
endif ()
find_package(Boost 1.70.0 REQUIRED COMPONENTS system thread)
file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "include/*.h" "include/*/*.h" "include/*.hpp" "include/*/*.hpp")
add_executable(BeamMP-Server ${source_files})
#find_package(Boost 1.70.0 REQUIRED COMPONENTS system thread)
target_include_directories(BeamMP-Server SYSTEM PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
find_package(Lua 5.3 REQUIRED)
target_include_directories(BeamMP-Server SYSTEM PUBLIC ${LUA_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
file(GLOB source_files "src/*.cpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "src/*/*.cpp")
add_executable(BeamMP-Server ${source_files})
target_include_directories(BeamMP-Server PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
find_package(Lua REQUIRED)
target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR})
if (UNIX)
target_link_libraries(BeamMP-Server curl z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES})
target_link_libraries(BeamMP-Server z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES} curl dl)
elseif (WIN32)
include(FindLua)
find_package(CURL CONFIG REQUIRED)
find_package(ZLIB REQUIRED)
target_link_libraries(BeamMP-Server PRIVATE urlmon ws2_32 CURL::libcurl ZLIB::ZLIB ${Boost_LINK_DIRS} ${LUA_LIBRARIES})
find_package(CURL CONFIG REQUIRED)
find_package(RapidJSON CONFIG REQUIRED)
target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS})
target_link_libraries(BeamMP-Server PRIVATE ws2_32 CURL::libcurl ZLIB::ZLIB ${LUA_LIBRARIES})
#${Boost_LINK_DIRS}
endif ()

1
LICENSE Normal file
View File

@@ -0,0 +1 @@
Copyright (c) 2019-present Anonymous275. BeamMP Server code is not in the public domain and is not free software. One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries, the only permission that has been granted is to use the software in its compiled form as distributed from the BeamMP.com website. Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.

View File

@@ -1,36 +1,41 @@
# BeamNG-MP-Server
# BeamMP-Server
## Unix specific build instructions
The Server is the way we link client to each other and handle authentication, compression, and data management. It also allows lua plugins, that system is always being reviewed and improved with detailed instructions on wiki.beammp.com.
1. You need boost >= 1.70.0
## Supported Operating Systems
Check with your ditro's package manager whether it provides this. If it does, you should use that.
The code itself supports (latest stable) Linux and Windows. In terms of actual build support, for now we only distribute windows binaries and instructions to build on Debian 10 (stable). For any other distro or OS, you just have to find the same libraries listed in the Linux Build [Prerequisites](#prerequisites) further down the page, and it should build fine. We don't currently support ARM or any big-endian architectures.
Recommended compilers: MSVC, GCC.
If it doesnt provide it or you want to link it statically (like we do with our releases), then you have to do this:
## Linux / POSIX specific build instructions
download the latest boost source code.
Then, go to the downloaded directory and run
```sh
b2 link=static runtime-link=static threading=multi
```
And then either symlink, edit CMakeLists to find it, or simply run
```sh
b2 link=static runtime-link=static threading=multi install
```
(warning: installs boost into your system, you might not want this).
Currently only linux and windows are supported (generally). On systems to which we do not provide binaries (so anything but windows), you are allowed to compile the program and use it. Other restrictions, such as not being allowed to distribute those binaries, still apply (see [copyright notice](#copyright)).
Then on invocation of cmake, ensure that you define `Boost_USE_STATIC_RUNTIME=ON`.
### Prerequisites
All package names are ones found in debian's (debian 10 stable) repositories, but will exist under similar names in other distros. Feel free to PR your own guide for a different distro.
2. Building
- `git`
- `make`
- `cmake`
- `g++` (must support ISO C++17)
- `liblua5.3`
- `libz-dev`
- `rapidjson-dev`
- `libcurl4-openssl-dev` (or other `libcurl4-*-dev`)
Run cmake, and then make.
### How to build
Example:
1. Make sure you have all [prerequisites](#prerequisites) installed
2. Clone the repository in a location of your choice with `git clone --recursive https://github.com/BeamMP/BeamMP-Server`
3. `cd` into it with `cd BeamMP-Server`
4. Run `cmake .` (with `.`)
5. Run `make`
6. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server`. Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server.
```bash
~/src/Server $ cmake -S . -B bin -DCMAKE_BUILD_TYPE=Release
...
~/src/Server $ make -C bin -j 5
```
*tip: to run the server in the background, simply (in bash, zsh, etc) run:* `nohup ./BeamMP-Server &`*.*
## Copyright
Copyright (c) 2019-present Anonymous275. BeamMP Server code is not in the public domain and is not free software. One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries, the only permission that has been granted is to use the software in its compiled form as distributed from the BeamMP.com website. Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.

Binary file not shown.

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/8/2020
///
@@ -10,13 +14,13 @@
#define SOCKET int
#endif
#include "CustomAssert.h"
#include <string>
#include <vector>
#include <algorithm>
#include <chrono>
#include <set>
#include <algorithm>
#include <string>
#include <vector>
struct VData{
struct VData {
int ID = -1;
std::string Data;
};
@@ -24,43 +28,45 @@ struct VData{
class Client {
private:
std::set<std::unique_ptr<VData>> VehicleData; //ID and Data;
std::string Name = Sec("Unknown Client");
std::string Name = "Unknown Client";
SOCKET SOCK[2] { SOCKET(-1) };
sockaddr_in UDPADDR;
std::string Role;
std::string DID;
SOCKET TCPSOCK;
int Status = 0;
int ID = -1;
public:
void AddNewCar(int ident,const std::string& Data);
void SetCarData(int ident,const std::string&Data);
void SetName(const std::string& name);
void SetRole(const std::string& role);
void SetDID(const std::string& did);
std::string GetCarData(int ident);
void SetUDPAddr(sockaddr_in Addr);
std::set<std::unique_ptr<VData>>& GetAllCars();
const std::set<std::unique_ptr<VData>>& GetAllCars() const;
void SetTCPSock(SOCKET CSock);
void SetStatus(int status);
void DeleteCar(int ident);
sockaddr_in GetUDPAddr();
bool isConnected = false;
std::string GetRole();
std::string GetName();
bool isSynced = false;
std::string GetDID();
SOCKET GetTCPSock();
void SetID(int ID);
bool isGuest = false;
void AddNewCar(int ident, const std::string& Data);
void SetCarData(int ident, const std::string& Data);
std::set<std::unique_ptr<VData>>& GetAllCars();
void SetName(const std::string& name) { Name = name; }
void SetRoles(const std::string& role) { Role = role; }
std::string GetCarData(int ident);
void SetUDPAddr(sockaddr_in Addr) { UDPADDR = Addr; }
void SetDownSock(SOCKET CSock) { SOCK[1] = CSock; }
void SetTCPSock(SOCKET CSock) { SOCK[0] = CSock; }
void SetStatus(int status) { Status = status; }
void DeleteCar(int ident);
sockaddr_in GetUDPAddr() { return UDPADDR; }
std::string GetRoles() { return Role; }
std::string GetName() { return Name; }
SOCKET GetDownSock() { return SOCK[1]; }
SOCKET GetTCPSock() { return SOCK[0]; }
void SetID(int ID) { this->ID = ID; }
int GetOpenCarID();
int GetCarCount();
void ClearCars();
int GetStatus();
int GetID();
int GetStatus() { return Status; }
int GetID() { return ID; }
};
struct ClientInterface{
struct ClientInterface {
std::set<std::unique_ptr<Client>> Clients;
void RemoveClient(Client*& c){
void RemoveClient(Client*& c) {
Assert(c);
c->ClearCars();
auto Iter = std::find_if(Clients.begin(), Clients.end(), [&](auto& ptr) {
@@ -73,11 +79,11 @@ struct ClientInterface{
Clients.erase(Iter);
c = nullptr;
}
void AddClient(Client*&& c){
void AddClient(Client*&& c) {
Assert(c);
Clients.insert(std::move(std::unique_ptr<Client>(c)));
Clients.insert(std::unique_ptr<Client>(c));
}
int Size(){
int Size() {
return int(Clients.size());
}
};

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/24/2020
///

View File

@@ -1,7 +1,11 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/18/2020
///
#pragma once
#include <string>
std::string HttpRequest(const std::string& IP, int port);
std::string PostHTTP(const std::string& IP, const std::string& Fields);
std::string PostHTTP(const std::string& IP, const std::string& Fields, bool json);

12
include/Json.h Normal file
View File

@@ -0,0 +1,12 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 11/27/2020
///
#pragma once
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
namespace json = rapidjson;

View File

@@ -1,8 +1,12 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 4/2/2020.
///
#pragma once
#include "Security/Xor.h"
#include <iostream>
#include <mutex>
#include <string>
@@ -10,7 +14,6 @@ void InitLog();
#define DebugPrintTID() DebugPrintTIDInternal(__func__, false)
void DebugPrintTIDInternal(const std::string& func, bool overwrite = true); // prints the current thread id in debug mode, to make tracing of crashes and asserts easier
void ConsoleOut(const std::string& msg);
void QueueAbort();
void except(const std::string& toPrint);
void debug(const std::string& toPrint);
void error(const std::string& toPrint);

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/20/2020
///
@@ -72,6 +76,6 @@ public:
void SetStopThread(bool StopThread) { _StopThread = StopThread; }
bool GetStopThread() const { return _StopThread; }
};
int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> args);
int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait);
std::any CallFunction(Lua* lua, const std::string& FuncName, std::shared_ptr<LuaArg> args);
std::any TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::shared_ptr<LuaArg> arg, bool Wait);
extern std::set<std::unique_ptr<Lua>> PluginEngine;

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/31/2020
///
@@ -7,13 +11,15 @@
void TCPServerMain();
void UpdatePlayers();
void OnConnect(Client* c);
void InitClient(Client* c);
void TCPClient(Client* c);
std::string TCPRcv(Client* c);
void SyncResources(Client* c);
[[noreturn]] void UDPServerMain();
void OnDisconnect(Client* c, bool kicked);
void UDPSend(Client* c, std::string Data);
void TCPSend(Client* c, const std::string& Data);
void SendLarge(Client* c, std::string Data);
bool TCPSend(Client* c, const std::string& Data);
void GParser(Client* c, const std::string& Packet);
std::string StaticReason(bool Set, const std::string& R);
void Respond(Client* c, const std::string& MSG, bool Rel);
void SendToAll(Client* c, const std::string& Data, bool Self, bool Rel);

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
@@ -7,15 +11,5 @@
#else
#include <WS2tcpip.h>
#endif
#include "Xor.h"
#include <string>
struct RSA {
int n = 0;
int e = 0;
int d = 0;
};
std::string RSA_E(const std::string& Data, int e, int n);
std::string RSA_E(const std::string& Data, RSA* k);
std::string RSA_D(const std::string& Data, RSA* k);
int Handle(EXCEPTION_POINTERS* ep, char* Origin);
RSA* GenKey();

View File

@@ -1,132 +0,0 @@
///
/// Created by Anonymous275 on 8/11/2020
///
#pragma once
#include <array>
#include <cstdarg>
#include <cstdio>
#include <string>
#define BEGIN_NAMESPACE(x) namespace x {
#define END_NAMESPACE }
BEGIN_NAMESPACE(XorCompileTime)
constexpr auto time = __TIME__;
constexpr auto seed = static_cast<int>(time[7]) + static_cast<int>(time[6]) * 10 + static_cast<int>(time[4]) * 60 + static_cast<int>(time[3]) * 600 + static_cast<int>(time[1]) * 3600 + static_cast<int>(time[0]) * 36000;
// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division
template <int N>
struct RandomGenerator {
private:
static constexpr unsigned a = 16807; // 7^5
static constexpr unsigned m = 2147483647; // 2^31 - 1
static constexpr unsigned s = RandomGenerator<N - 1>::value;
static constexpr unsigned lo = a * (s & 0xFFFFu); // Multiply lower 16 bits by 16807
static constexpr unsigned hi = a * (s >> 16u); // Multiply higher 16 bits by 16807
static constexpr unsigned lo2 = lo + ((hi & 0x7FFFu) << 16u); // Combine lower 15 bits of hi with lo's upper bits
static constexpr unsigned hi2 = hi >> 15u; // Discard lower 15 bits of hi
static constexpr unsigned lo3 = lo2 + hi;
public:
static constexpr unsigned max = m;
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};
template <>
struct RandomGenerator<0> {
static constexpr unsigned value = seed;
};
template <int N, int M>
struct RandomInt {
static constexpr auto value = RandomGenerator<N + 1>::value % M;
};
template <int N>
struct RandomChar {
static const char value = static_cast<char>(1 + RandomInt<N, 0x7F - 1>::value);
};
template <size_t N, int K, typename Char>
struct XorString {
private:
const char _key;
std::array<Char, N + 1> _encrypted;
constexpr Char enc(Char c) const {
return c ^ _key;
}
Char dec(Char c) const {
return c ^ _key;
}
public:
template <size_t... Is>
constexpr inline XorString(const Char* str, std::index_sequence<Is...>)
: _key(RandomChar<K>::value)
, _encrypted { enc(str[Is])... } { }
inline decltype(auto) decrypt() {
for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]);
}
_encrypted[N] = '\0';
return _encrypted.data();
}
};
static auto w_printf = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
};
static auto w_printf_s = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
};
/*static auto w_sprintf = [](char* buf, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
};*/
/*static auto w_sprintf_ret = [](char* buf, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(buf, fmt, args);
va_end(args);
return ret;
};*/
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsnprintf(buf, buf_size, fmt, args);
va_end(args);
};
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsnprintf(buf, buf_size, fmt, args);
va_end(args);
return ret;
};
#define Sec(s) [] { constexpr XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
#define SecW(s) [] { constexpr XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
END_NAMESPACE

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///

View File

@@ -12,8 +12,9 @@
#include <unistd.h>
// ZeroMemory is just a {0} or a memset(addr, 0, len), and it's a macro on MSVC
inline void ZeroMemory(void* dst, size_t len) {
Assert(std::memset(dst, 0, len) != nullptr);
inline void ZeroMemory([[maybe_unused]] void* dst, [[maybe_unused]] size_t len) {
[[maybe_unused]] auto res = std::memset(dst, 0, len);
Assert(res != nullptr);
}
// provides unix equivalent of closesocket call in win32
inline void CloseSocketProper(int socket) {
@@ -30,7 +31,6 @@ inline void CloseSocketProper(int socket) {
#endif
#else // win32
inline void CloseSocketProper(uint64_t socket) {
shutdown(socket, SD_BOTH);
closesocket(socket);

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/15/2020
///

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 10/29/2020
///
@@ -25,20 +29,17 @@ std::mutex MLock;
std::unique_ptr<Lua> LuaConsole;
void HandleInput(const std::string& cmd) {
std::cout << std::endl;
if (cmd == Sec("exit")) {
if (cmd == ("exit")) {
_Exit(0);
} else if (cmd == Sec("clear") || cmd == Sec("cls")) {
} else if (cmd == ("clear") || cmd == ("cls")) {
// 2J is clearscreen, H is reset position to top-left
ConsoleOut(Sec("\x1b[2J\x1b[H"));
ConsoleOut(("\x1b[2J\x1b[H"));
} else {
LuaConsole->Execute(cmd);
}
}
void ProcessOut() {
static size_t len = 2;
if (QConsoleOut.empty() && len == CInputBuff.length())
return;
printf("%c[2K\r", 27);
for (const std::string& msg : QConsoleOut)
if (!msg.empty())
@@ -47,7 +48,6 @@ void ProcessOut() {
QConsoleOut.clear();
MLock.unlock();
std::cout << "> " << CInputBuff << std::flush;
len = CInputBuff.length();
}
void ConsoleOut(const std::string& msg) {
@@ -99,37 +99,56 @@ char _getch(void) {
#endif // WIN32
void SetupConsole() {
#if defined(WIN32) && !defined(DEBUG)
#if defined(WIN32)
DWORD outMode = 0;
HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (stdoutHandle == INVALID_HANDLE_VALUE) {
error("Invalid handle");
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(GetLastError());
error("Invalid console handle! Inputs will not work properly");
return;
}
if (!GetConsoleMode(stdoutHandle, &outMode)) {
error("Invalid console mode");
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(GetLastError());
error("Invalid console mode! Inputs will not work properly");
return;
}
// Enable ANSI escape codes
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(stdoutHandle, outMode)) {
error("failed to set console mode");
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(GetLastError());
error("failed to set console mode! Inputs will not work properly");
return;
}
#else
#endif // WIN32
}
static std::vector<std::string> ConsoleHistory {};
// buffer used to revert back to what we were writing when we go all the way forward in history
static std::string LastInputBuffer {};
static size_t ConsoleHistoryReadIndex { 0 };
static inline void ConsoleHistoryAdd(const std::string& cmd) {
LastInputBuffer.clear();
ConsoleHistory.push_back(cmd);
ConsoleHistoryReadIndex = ConsoleHistory.size();
}
static inline void ConsoleHistoryEnsureBounds() {
if (ConsoleHistoryReadIndex >= ConsoleHistory.size()) {
ConsoleHistoryReadIndex = ConsoleHistory.size() - 1;
}
}
static inline void ConsoleHistoryGoBack() {
if (ConsoleHistoryReadIndex > 0) {
--ConsoleHistoryReadIndex;
ConsoleHistoryEnsureBounds();
}
}
static inline void ConsoleHistoryGoForward() {
++ConsoleHistoryReadIndex;
ConsoleHistoryEnsureBounds();
}
static std::string CompositeInput;
static bool CompositeInputExpected { false };
@@ -141,11 +160,8 @@ static void ProcessCompositeInput() {
#endif // WIN32
// UP ARROW
// info(std::to_string(ConsoleHistoryReadIndex));
if (!ConsoleHistory.empty()) {
if (ConsoleHistoryReadIndex != 0) {
ConsoleHistoryReadIndex -= 1;
}
ConsoleHistoryGoBack();
CInputBuff = ConsoleHistory.at(ConsoleHistoryReadIndex);
}
#ifdef WIN32
@@ -156,12 +172,11 @@ static void ProcessCompositeInput() {
// DOWN ARROW
if (!ConsoleHistory.empty()) {
if (ConsoleHistoryReadIndex != ConsoleHistory.size() - 1) {
ConsoleHistoryReadIndex += 1;
CInputBuff = ConsoleHistory.at(ConsoleHistoryReadIndex);
if (ConsoleHistoryReadIndex == ConsoleHistory.size() - 1) {
CInputBuff = LastInputBuffer;
} else {
CInputBuff = "";
ConsoleHistoryReadIndex = ConsoleHistory.size();
ConsoleHistoryGoForward();
CInputBuff = ConsoleHistory.at(ConsoleHistoryReadIndex);
}
}
} else {
@@ -171,17 +186,25 @@ static void ProcessCompositeInput() {
// ensure history doesnt grow too far beyond a max
static constexpr size_t MaxHistory = 10;
if (ConsoleHistory.size() > 2 * MaxHistory) {
std::vector<std::string> NewHistory(ConsoleHistory.begin() + ConsoleHistory.size() - MaxHistory, ConsoleHistory.end());
decltype(ConsoleHistory) NewHistory(ConsoleHistory.begin() + ConsoleHistory.size() - MaxHistory, ConsoleHistory.end());
ConsoleHistory = std::move(NewHistory);
ConsoleHistoryReadIndex = ConsoleHistory.size();
}
}
[[noreturn]] void ReadCin() {
void ReadCin() {
DebugPrintTID();
size_t null_byte_counter = 0;
while (true) {
int In = _getch();
// info(std::to_string(In));
//info(std::to_string(In));
if (In == 0) {
++null_byte_counter;
if (null_byte_counter > 50) {
info(("too many null bytes in input, this is now assumed to be a background thread - console input is now disabled"));
break;
}
}
if (CompositeInputExpected) {
CompositeInput += char(In);
#ifdef WIN32
@@ -224,12 +247,14 @@ static void ProcessCompositeInput() {
// ignore
} else {
CInputBuff += char(In);
LastInputBuffer = CInputBuff;
}
}
}
void ConsoleInit() {
SetupConsole();
LuaConsole = std::make_unique<Lua>(true);
LuaConsole->Init();
printf("> ");
std::thread In(ReadCin);
In.detach();

View File

@@ -1,102 +1,23 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
#include "Security/Enc.h"
#include "CustomAssert.h"
#include "Settings.h"
//#include <windows.h>
#include "Logger.h"
#include <random>
#include <sstream>
#include <thread>
int Rand() {
std::random_device r;
std::default_random_engine e1(r());
std::uniform_int_distribution<int> uniform_dist(1, 5000);
return uniform_dist(e1);
}
int log_power(int n, unsigned int p, int mod) {
int result = 1;
for (; p; p >>= 1u) {
if (p & 1u)
result = int((1LL * result * n) % mod);
n = int((1LL * n * n) % mod);
}
return result;
}
bool rabin_miller(int n) {
bool ok = true;
for (int i = 1; i <= 5 && ok; i++) {
int a = Rand() + 1;
int result = log_power(a, n - 1, n);
ok &= (result == 1);
}
return ok;
}
int generate_prime() {
int generated = Rand();
while (!rabin_miller(generated))
generated = Rand();
return generated;
}
int gcd(int a, int b) {
while (b) {
int r = a % b;
a = b;
b = r;
}
return a;
}
int generate_coprime(int n) {
int generated = Rand();
while (gcd(n, generated) != 1)
generated = Rand();
return generated;
}
std::pair<int, int> euclid_extended(int a, int b) {
if (!b)
return { 1, 0 };
auto result = euclid_extended(b, a % b);
return { result.second, result.first - (a / b) * result.second };
}
int modular_inverse(int n, int mod) {
int inverse = euclid_extended(n, mod).first;
while (inverse < 0)
inverse += mod;
return inverse;
}
RSA* GenKey() {
int p, q;
p = generate_prime();
q = generate_prime();
int n = p * q;
int phi = (p - 1) * (q - 1);
int e = generate_coprime(phi);
int d = modular_inverse(e, phi);
return new RSA { n, e, d };
}
int Enc(int value, int e, int n) {
return log_power(value, e, n);
}
int Dec(int value, int d, int n) {
return log_power(value, d, n);
}
#ifdef WIN32
#include <WS2tcpip.h>
int Handle(EXCEPTION_POINTERS* ep, char* Origin) {
//Assert(false);
Assert(false);
std::stringstream R;
R << Sec("Code : ") << std::hex
R << ("Code : ") << std::hex
<< ep->ExceptionRecord->ExceptionCode
<< std::dec << Sec(" Origin : ") << Origin;
<< std::dec << (" Origin : ") << Origin;
except(R.str());
return 1;
}
@@ -104,29 +25,3 @@ int Handle(EXCEPTION_POINTERS* ep, char* Origin) {
// stub
int Handle(EXCEPTION_POINTERS*, char*) { return 1; }
#endif // WIN32
std::string RSA_E(const std::string& Data, RSA* k) {
std::stringstream stream;
for (const char& c : Data) {
stream << std::hex << Enc(uint8_t(c), k->e, k->n) << "g";
}
return stream.str();
}
std::string RSA_E(const std::string& Data, int e, int n) {
std::stringstream stream;
for (const char& c : Data) {
stream << std::hex << Enc(uint8_t(c), e, n) << "g";
}
return stream.str();
}
std::string RSA_D(const std::string& Data, RSA* k) {
std::stringstream ss(Data);
std::string token, ret;
while (std::getline(ss, token, 'g')) {
if (token.find_first_not_of(Sec("0123456789abcdef")) != std::string::npos)
return "";
int c = std::stoi(token, nullptr, 16);
ret += char(Dec(c, k->d, k->n));
}
return ret;
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
@@ -91,13 +95,13 @@ void LoadConfig(std::ifstream& IFS) {
index++;
}
if (index - 1 < 11) {
error(Sec("Outdated/Incorrect config please remove it server will close in 5 secs"));
error(("Outdated/Incorrect config please remove it server will close in 5 secs"));
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(0);
}
IFS.close();
IFS.open(Sec("Server.cfg"));
info(Sec("Config found updating values"));
IFS.open(("Server.cfg"));
info(("Config found updating values"));
index = 1;
while (getline(IFS, line)) {
if (line.rfind('#', 0) != 0 && line.rfind(' ', 0) != 0) { //Checks if it starts as Comment
@@ -109,42 +113,44 @@ void LoadConfig(std::ifstream& IFS) {
}
void GenerateConfig() {
std::ofstream FileStream;
FileStream.open(Sec("Server.cfg"));
FileStream << Sec("# This is the BeamMP Server Configuration File v0.60\n"
"Debug = false # true or false to enable debug console output\n"
"Private = true # Private?\n"
"Port = 30814 # Port to run the server on UDP and TCP\n"
"Cars = 1 # Max cars for every player\n"
"MaxPlayers = 10 # Maximum Amount of Clients\n"
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
"Name = \"BeamMP New Server\" # Server Name\n"
"Desc = \"BeamMP Default Description\" # Server Description\n"
"use = \"Resources\" # Resource file name\n"
"AuthKey = \"\" # Auth Key");
FileStream.open(("Server.cfg"));
FileStream << ("# This is the BeamMP Server Configuration File v0.60\n"
"Debug = false # true or false to enable debug console output\n"
"Private = true # Private?\n"
"Port = 30814 # Port to run the server on UDP and TCP\n"
"Cars = 1 # Max cars for every player\n"
"MaxPlayers = 10 # Maximum Amount of Clients\n"
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
"Name = \"BeamMP New Server\" # Server Name\n"
"Desc = \"BeamMP Default Description\" # Server Description\n"
"use = \"Resources\" # Resource file name\n"
"AuthKey = \"\" # Auth Key");
FileStream.close();
}
void Default() {
info(Sec("Config not found generating default"));
info(("Config not found generating default"));
GenerateConfig();
error(Sec("You are required to input the AuthKey"));
error(("You are required to input the AuthKey"));
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(0);
}
void DebugData() {
debug(std::string(Sec("Debug : ")) + (Debug ? "true" : "false"));
debug(std::string(Sec("Private : ")) + (Private ? "true" : "false"));
debug(Sec("Port : ") + std::to_string(Port));
debug(Sec("Max Cars : ") + std::to_string(MaxCars));
debug(Sec("MaxPlayers : ") + std::to_string(MaxPlayers));
debug(Sec("MapName : ") + MapName);
debug(Sec("ServerName : ") + ServerName);
debug(Sec("ServerDesc : ") + ServerDesc);
debug(Sec("File : ") + Resource);
debug(Sec("Key length: ") + std::to_string(Key.length()));
debug(std::string("Debug : ") + (Debug ? "true" : "false"));
debug(std::string("Private : ") + (Private ? "true" : "false"));
debug("Port : " + std::to_string(Port));
debug("Max Cars : " + std::to_string(MaxCars));
debug("MaxPlayers : " + std::to_string(MaxPlayers));
debug("MapName : " + MapName);
debug("ServerName : " + ServerName);
debug("ServerDesc : " + ServerDesc);
debug("File : " + Resource);
debug("Key length: " + std::to_string(Key.length()));
}
void InitConfig() {
////TODO: Move to json after update 4
std::ifstream IFS;
IFS.open(Sec("Server.cfg"));
IFS.open(("Server.cfg"));
if (IFS.good())
LoadConfig(IFS);
else
@@ -152,7 +158,7 @@ void InitConfig() {
if (IFS.is_open())
IFS.close();
if (Key.empty()) {
error(Sec("No AuthKey was found"));
error(("No AuthKey was found"));
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(0);
}

View File

@@ -1,10 +1,13 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
#include "Client.hpp"
#include "Curl/Http.h"
#include "Logger.h"
#include "Security/Enc.h"
#include "Settings.h"
#include <chrono>
#include <future>
@@ -34,19 +37,18 @@ std::string GenerateCall() {
return Ret.str();
}
std::string RunPromise(const std::string& IP, const std::string& R) {
std::packaged_task<std::string()> task([&]() { return PostHTTP(IP, R); });
std::packaged_task<std::string()> task([&] { return PostHTTP(IP, R, false); });
std::future<std::string> f1 = task.get_future();
std::thread t(std::move(task));
t.detach();
auto status = f1.wait_for(std::chrono::seconds(10));
auto status = f1.wait_for(std::chrono::seconds(15));
if (status != std::future_status::timeout)
return f1.get();
error(Sec("Backend system Timeout please try again later"));
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(0);
error("Backend system Timeout please try again later");
return "";
}
void Heartbeat() {
[[noreturn]] void Heartbeat() {
DebugPrintTID();
std::string R, T;
bool isAuth = false;
@@ -54,29 +56,26 @@ void Heartbeat() {
R = GenerateCall();
if (!CustomIP.empty())
R += "&ip=" + CustomIP;
std::string link = Sec("https://beammp.com/heartbeatv2");
std::string link = "https://beammp.com/heartbeatv2";
T = RunPromise(link, R);
if (T.find_first_not_of(Sec("20")) != std::string::npos) {
if (T.substr(0, 2) != "20") {
//Backend system refused server startup!
std::this_thread::sleep_for(std::chrono::seconds(10));
std::string Backup = Sec("https://backup1.beammp.com/heartbeatv2");
std::string Backup = "https://backup1.beammp.com/heartbeatv2";
T = RunPromise(Backup, R);
if (T.find_first_not_of(Sec("20")) != std::string::npos) {
error(Sec("Backend system refused server! Check your AuthKey"));
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(-1);
if (T.substr(0, 2) != "20") {
warn("Backend system refused server! Server might not show in the public list");
}
}
//Server Authenticated
if (T.length() == 4)
info(Sec("Server authenticated"));
R.clear();
T.clear();
if (!isAuth) {
WebsocketInit();
if (T.length() == 4)info(("Authenticated!"));
else info(("Resumed authenticated session!"));
isAuth = true;
}
std::this_thread::sleep_for(std::chrono::seconds(3));
//std::this_thread::sleep_for(std::chrono::seconds(5));
}
}
void HBInit() {

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
@@ -15,22 +19,21 @@ std::string FileList;
int ModsLoaded = 0;
void InitRes() {
std::string Path = Resource + Sec("/Client");
std::string Path = Resource + "/Client";
if (!fs::exists(Path))
fs::create_directory(Path);
for (const auto& entry : fs::directory_iterator(Path)) {
auto pos = entry.path().string().find(Sec(".zip"));
auto pos = entry.path().string().find(".zip");
if (pos != std::string::npos) {
if (entry.path().string().length() - pos == 4) {
FileList += entry.path().string() + ";";
FileSizes += std::to_string(fs::file_size(entry.path())) + ";";
MaxModSize += fs::file_size(entry.path());
FileSizes += std::to_string(uint64_t(fs::file_size(entry.path()))) + ";";
MaxModSize += uint64_t(fs::file_size(entry.path()));
ModsLoaded++;
}
}
}
std::replace(FileList.begin(), FileList.end(), '\\', '/');
if (ModsLoaded) {
info(Sec("Loaded ") + std::to_string(ModsLoaded) + Sec(" Mods"));
}
if (ModsLoaded)
info("Loaded " + std::to_string(ModsLoaded) + " Mods");
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/28/2020
///
@@ -9,24 +13,22 @@
std::string CustomIP;
std::string GetSVer() {
static std::string r = Sec("1.0");
return r;
return "1.20";
}
std::string GetCVer() {
static std::string r = Sec("1.70");
return r;
return "1.80";
}
void Args(int argc, char* argv[]) {
info(Sec("BeamMP Server Running version ") + GetSVer());
info("BeamMP Server Running version " + GetSVer());
if (argc > 1) {
CustomIP = argv[1];
size_t n = std::count(CustomIP.begin(), CustomIP.end(), '.');
auto p = CustomIP.find_first_not_of(Sec(".0123456789"));
if (p != std::string::npos || n != 3 || CustomIP.substr(0, 3) == Sec("127")) {
auto p = CustomIP.find_first_not_of((".0123456789"));
if (p != std::string::npos || n != 3 || CustomIP.substr(0, 3) == ("127")) {
CustomIP.clear();
warn(Sec("IP Specified is invalid! Ignoring"));
warn("IP Specified is invalid! Ignoring");
} else
info(Sec("Server started with custom IP"));
info("Server started with custom IP");
}
}
void InitServer(int argc, char* argv[]) {

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/20/2020
///
@@ -24,9 +28,9 @@ bool NewFile(const std::string& Path) {
void RegisterFiles(const std::string& Path, bool HotSwap) {
std::string Name = Path.substr(Path.find_last_of('\\') + 1);
if (!HotSwap)
info(Sec("Loading plugin : ") + Name);
info(("Loading plugin : ") + Name);
for (const auto& entry : fs::directory_iterator(Path)) {
auto pos = entry.path().string().find(Sec(".lua"));
auto pos = entry.path().string().find((".lua"));
if (pos != std::string::npos && entry.path().string().length() - pos == 4) {
if (!HotSwap || NewFile(entry.path().string())) {
auto FileName = entry.path().string();
@@ -35,7 +39,7 @@ void RegisterFiles(const std::string& Path, bool HotSwap) {
PluginEngine.insert(std::move(ScriptToInsert));
Script.Init();
if (HotSwap)
info(Sec("[HOTSWAP] Added : ") + Script.GetFileName().substr(Script.GetFileName().find('\\')));
info(("[HOTSWAP] Added : ") + Script.GetFileName().substr(Script.GetFileName().find('\\')));
}
}
}
@@ -57,12 +61,12 @@ void FolderList(const std::string& Path, bool HotSwap) {
if (stat(Script->GetFileName().c_str(), &Info) != 0) {
Script->SetStopThread(true);
PluginEngine.erase(Script);
info(Sec("[HOTSWAP] Removed : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
info(("[HOTSWAP] Removed removed script due to delete"));
break;
}
if (Script->GetLastWrite() != fs::last_write_time(Script->GetFileName())) {
Script->SetStopThread(true);
info(Sec("[HOTSWAP] Updated : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
info(("[HOTSWAP] Updated Scripts due to edit"));
Script->SetLastWrite(fs::last_write_time(Script->GetFileName()));
Script->Reload();
}
@@ -77,12 +81,12 @@ void InitLua() {
if (!fs::exists(Resource)) {
fs::create_directory(Resource);
}
std::string Path = Resource + Sec("/Server");
std::string Path = Resource + ("/Server");
if (!fs::exists(Path)) {
fs::create_directory(Path);
}
FolderList(Path, false);
std::thread t1(HotSwaps, Path);
t1.detach();
info(Sec("Lua system online"));
info(("Lua system online"));
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/19/2020
///
@@ -14,10 +18,10 @@
#include <optional>
#include <utility>
std::unique_ptr<LuaArg> CreateArg(lua_State* L, int T, int S) {
std::shared_ptr<LuaArg> CreateArg(lua_State* L, int T, int S) {
if (S > T)
return nullptr;
std::unique_ptr<LuaArg> temp(new LuaArg);
std::shared_ptr<LuaArg> temp(new LuaArg);
for (int C = S; C <= T; C++) {
if (lua_isstring(L, C)) {
temp->args.emplace_back(std::string(lua_tostring(L, C)));
@@ -46,18 +50,18 @@ void SendError(lua_State* L, const std::string& msg) {
auto MaybeS = GetScript(L);
std::string a;
if (!MaybeS.has_value()) {
a = Sec("_Console");
a = ("_Console");
} else {
Lua& S = MaybeS.value();
a = fs::path(S.GetFileName()).filename().string();
}
warn(a + Sec(" | Incorrect Call of ") + msg);
warn(a + (" | Incorrect Call of ") + msg);
}
int Trigger(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg) {
std::any Trigger(Lua* lua, const std::string& R, std::shared_ptr<LuaArg> arg) {
std::lock_guard<std::mutex> lockGuard(lua->Lock);
std::packaged_task<int(std::unique_ptr<LuaArg>)> task([lua, R](std::unique_ptr<LuaArg> arg) { return CallFunction(lua, R, std::move(arg)); });
std::future<int> f1 = task.get_future();
std::thread t(std::move(task), std::move(arg));
std::packaged_task<std::any(std::shared_ptr<LuaArg>)> task([lua, R](std::shared_ptr<LuaArg> arg) { return CallFunction(lua, R, arg); });
std::future<std::any> f1 = task.get_future();
std::thread t(std::move(task), arg);
t.detach();
auto status = f1.wait_for(std::chrono::seconds(5));
if (status != std::future_status::timeout)
@@ -65,11 +69,11 @@ int Trigger(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg) {
SendError(lua->GetState(), R + " took too long to respond");
return 0;
}
int FutureWait(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg, bool Wait) {
std::any FutureWait(Lua* lua, const std::string& R, std::shared_ptr<LuaArg> arg, bool Wait) {
Assert(lua);
std::packaged_task<int(std::unique_ptr<LuaArg>)> task([lua, R](std::unique_ptr<LuaArg> arg) { return Trigger(lua, R, std::move(arg)); });
std::future<int> f1 = task.get_future();
std::thread t(std::move(task), std::move(arg));
std::packaged_task<std::any(std::shared_ptr<LuaArg>)> task([lua, R](std::shared_ptr<LuaArg> arg) { return Trigger(lua, R, arg); });
std::future<std::any> f1 = task.get_future();
std::thread t(std::move(task), arg);
t.detach();
int T = 0;
if (Wait)
@@ -79,24 +83,39 @@ int FutureWait(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg, bool
return f1.get();
return 0;
}
int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait) {
int R = 0;
std::any TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::shared_ptr<LuaArg> arg, bool Wait) {
std::any R;
std::string Type;
int Ret = 0;
for (auto& Script : PluginEngine) {
if (Script->IsRegistered(Event)) {
if (local) {
if (Script->GetPluginName() == Caller->GetPluginName()) {
R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait);
Type = R.type().name();
if (Type.find("int") != std::string::npos) {
if (std::any_cast<int>(R))
Ret++;
} else if (Event == "onPlayerAuth")
return R;
}
} else
R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
} else {
R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait);
Type = R.type().name();
if (Type.find("int") != std::string::npos) {
if (std::any_cast<int>(R))
Ret++;
} else if (Event == "onPlayerAuth")
return R;
}
}
}
return R;
return Ret;
}
bool ConsoleCheck(lua_State* L, int r) {
if (r != LUA_OK) {
std::string msg = lua_tostring(L, -1);
warn(Sec("_Console | ") + msg);
warn(("_Console | ") + msg);
return false;
}
return true;
@@ -125,7 +144,7 @@ int lua_RegisterEvent(lua_State* L) {
if (Args == 2 && lua_isstring(L, 1) && lua_isstring(L, 2)) {
Script.RegisterEvent(lua_tostring(L, 1), lua_tostring(L, 2));
} else
SendError(L, Sec("RegisterEvent invalid argument count expected 2 got ") + std::to_string(Args));
SendError(L, ("RegisterEvent invalid argument count expected 2 got ") + std::to_string(Args));
return 0;
}
int lua_TriggerEventL(lua_State* L) {
@@ -137,9 +156,9 @@ int lua_TriggerEventL(lua_State* L) {
if (lua_isstring(L, 1)) {
TriggerLuaEvent(lua_tostring(L, 1), true, &Script, CreateArg(L, Args, 2), false);
} else
SendError(L, Sec("TriggerLocalEvent wrong argument [1] need string"));
SendError(L, ("TriggerLocalEvent wrong argument [1] need string"));
} else {
SendError(L, Sec("TriggerLocalEvent not enough arguments expected 1 got 0"));
SendError(L, ("TriggerLocalEvent not enough arguments expected 1 got 0"));
}
return 0;
}
@@ -153,9 +172,9 @@ int lua_TriggerEventG(lua_State* L) {
if (lua_isstring(L, 1)) {
TriggerLuaEvent(lua_tostring(L, 1), false, &Script, CreateArg(L, Args, 2), false);
} else
SendError(L, Sec("TriggerGlobalEvent wrong argument [1] need string"));
SendError(L, ("TriggerGlobalEvent wrong argument [1] need string"));
} else
SendError(L, Sec("TriggerGlobalEvent not enough arguments"));
SendError(L, ("TriggerGlobalEvent not enough arguments"));
return 0;
}
@@ -220,13 +239,13 @@ int lua_CreateThread(lua_State* L) {
std::thread t1(CallAsync, &Script, STR, U);
t1.detach();
} else
SendError(L, Sec("CreateThread wrong argument [2] number must be between 1 and 500"));
SendError(L, ("CreateThread wrong argument [2] number must be between 1 and 500"));
} else
SendError(L, Sec("CreateThread wrong argument [2] need number"));
SendError(L, ("CreateThread wrong argument [2] need number"));
} else
SendError(L, Sec("CreateThread wrong argument [1] need string"));
SendError(L, ("CreateThread wrong argument [1] need string"));
} else
SendError(L, Sec("CreateThread not enough arguments"));
SendError(L, ("CreateThread not enough arguments"));
return 0;
}
int lua_Sleep(lua_State* L) {
@@ -234,7 +253,7 @@ int lua_Sleep(lua_State* L) {
int t = int(lua_tonumber(L, 1));
std::this_thread::sleep_for(std::chrono::milliseconds(t));
} else {
SendError(L, Sec("Sleep not enough arguments"));
SendError(L, ("Sleep not enough arguments"));
return 0;
}
return 1;
@@ -256,7 +275,7 @@ int lua_isConnected(lua_State* L) {
else
return 0;
} else {
SendError(L, Sec("isConnected not enough arguments"));
SendError(L, ("isConnected not enough arguments"));
return 0;
}
return 1;
@@ -270,7 +289,7 @@ int lua_GetPlayerName(lua_State* L) {
else
return 0;
} else {
SendError(L, Sec("GetPlayerName not enough arguments"));
SendError(L, ("GetPlayerName not enough arguments"));
return 0;
}
return 1;
@@ -279,16 +298,16 @@ int lua_GetPlayerCount(lua_State* L) {
lua_pushinteger(L, CI->Size());
return 1;
}
int lua_GetDID(lua_State* L) {
int lua_GetGuest(lua_State* L) {
if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1));
Client* c = GetClient(ID);
if (c != nullptr)
lua_pushstring(L, c->GetDID().c_str());
lua_pushboolean(L, c->isGuest);
else
return 0;
} else {
SendError(L, Sec("GetDID not enough arguments"));
SendError(L, "GetGuest not enough arguments");
return 0;
}
return 1;
@@ -327,7 +346,7 @@ int lua_GetCars(lua_State* L) {
} else
return 0;
} else {
SendError(L, Sec("GetPlayerVehicles not enough arguments"));
SendError(L, ("GetPlayerVehicles not enough arguments"));
return 0;
}
return 1;
@@ -339,19 +358,16 @@ int lua_dropPlayer(lua_State* L) {
Client* c = GetClient(ID);
if (c == nullptr)
return 0;
if (c->GetRole() == Sec("MDEV"))
return 0;
std::string Reason;
if (Args > 1 && lua_isstring(L, 2)) {
Reason = std::string(Sec(" Reason : ")) + lua_tostring(L, 2);
Reason = std::string((" Reason : ")) + lua_tostring(L, 2);
}
Respond(c, "C:Server:You have been Kicked from the server! " + Reason, true);
c->SetStatus(-2);
info(Sec("Closing socket due to kick"));
info(("Closing socket due to kick"));
CloseSocketProper(c->GetTCPSock());
} else
SendError(L, Sec("DropPlayer not enough arguments"));
SendError(L, ("DropPlayer not enough arguments"));
return 0;
}
int lua_sendChat(lua_State* L) {
@@ -369,18 +385,18 @@ int lua_sendChat(lua_State* L) {
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
Respond(c, Packet, true);
} else
SendError(L, Sec("SendChatMessage invalid argument [1] invalid ID"));
SendError(L, ("SendChatMessage invalid argument [1] invalid ID"));
}
} else
SendError(L, Sec("SendChatMessage invalid argument [2] expected string"));
SendError(L, ("SendChatMessage invalid argument [2] expected string"));
} else
SendError(L, Sec("SendChatMessage invalid argument [1] expected number"));
SendError(L, ("SendChatMessage invalid argument [1] expected number"));
return 0;
}
int lua_RemoveVehicle(lua_State* L) {
int Args = lua_gettop(L);
if (Args != 2) {
SendError(L, Sec("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args));
SendError(L, ("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args));
return 0;
}
if ((lua_isinteger(L, 1) || lua_isnumber(L, 1)) && (lua_isinteger(L, 2) || lua_isnumber(L, 2))) {
@@ -388,18 +404,16 @@ int lua_RemoveVehicle(lua_State* L) {
int VID = int(lua_tointeger(L, 2));
Client* c = GetClient(PID);
if (c == nullptr) {
SendError(L, Sec("RemoveVehicle invalid Player ID"));
SendError(L, ("RemoveVehicle invalid Player ID"));
return 0;
}
if (c->GetRole() == "MDEV")
return 0;
if (!c->GetCarData(VID).empty()) {
std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID);
SendToAll(nullptr, Destroy, true, true);
c->DeleteCar(VID);
}
} else
SendError(L, Sec("RemoveVehicle invalid argument expected number"));
SendError(L, ("RemoveVehicle invalid argument expected number"));
return 0;
}
int lua_HWID(lua_State* L) {
@@ -409,19 +423,19 @@ int lua_HWID(lua_State* L) {
int lua_RemoteEvent(lua_State* L) {
int Args = lua_gettop(L);
if (Args != 3) {
SendError(L, Sec("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args));
SendError(L, ("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args));
return 0;
}
if (!lua_isnumber(L, 1)) {
SendError(L, Sec("TriggerClientEvent invalid argument [1] expected number"));
SendError(L, ("TriggerClientEvent invalid argument [1] expected number"));
return 0;
}
if (!lua_isstring(L, 2)) {
SendError(L, Sec("TriggerClientEvent invalid argument [2] expected string"));
SendError(L, ("TriggerClientEvent invalid argument [2] expected string"));
return 0;
}
if (!lua_isstring(L, 3)) {
SendError(L, Sec("TriggerClientEvent invalid argument [3] expected string"));
SendError(L, ("TriggerClientEvent invalid argument [3] expected string"));
return 0;
}
int ID = int(lua_tointeger(L, 1));
@@ -431,30 +445,35 @@ int lua_RemoteEvent(lua_State* L) {
else {
Client* c = GetClient(ID);
if (c == nullptr) {
SendError(L, Sec("TriggerClientEvent invalid Player ID"));
SendError(L, ("TriggerClientEvent invalid Player ID"));
return 0;
}
Respond(c, Packet, true);
}
return 0;
}
int lua_ServerExit(lua_State*) {
int lua_ServerExit(lua_State* L) {
if (lua_gettop(L) > 0) {
if (lua_isnumber(L, 1)) {
_Exit(int(lua_tointeger(L, 1)));
}
}
_Exit(0);
}
int lua_Set(lua_State* L) {
int Args = lua_gettop(L);
if (Args != 2) {
SendError(L, Sec("set invalid argument count expected 2 got ") + std::to_string(Args));
SendError(L, ("set invalid argument count expected 2 got ") + std::to_string(Args));
return 0;
}
if (!lua_isnumber(L, 1)) {
SendError(L, Sec("set invalid argument [1] expected number"));
SendError(L, ("set invalid argument [1] expected number"));
return 0;
}
auto MaybeSrc = GetScript(L);
std::string Name;
if (!MaybeSrc.has_value()) {
Name = Sec("_Console");
Name = ("_Console");
} else {
Name = MaybeSrc.value().get().GetPluginName();
}
@@ -463,54 +482,54 @@ int lua_Set(lua_State* L) {
case 0: //debug
if (lua_isboolean(L, 2)) {
Debug = lua_toboolean(L, 2);
info(Name + Sec(" | Debug -> ") + (Debug ? "true" : "false"));
info(Name + (" | Debug -> ") + (Debug ? "true" : "false"));
} else
SendError(L, Sec("set invalid argument [2] expected boolean for ID : 0"));
SendError(L, ("set invalid argument [2] expected boolean for ID : 0"));
break;
case 1: //private
if (lua_isboolean(L, 2)) {
Private = lua_toboolean(L, 2);
info(Name + Sec(" | Private -> ") + (Private ? "true" : "false"));
info(Name + (" | Private -> ") + (Private ? "true" : "false"));
} else
SendError(L, Sec("set invalid argument [2] expected boolean for ID : 1"));
SendError(L, ("set invalid argument [2] expected boolean for ID : 1"));
break;
case 2: //max cars
if (lua_isnumber(L, 2)) {
MaxCars = int(lua_tointeger(L, 2));
info(Name + Sec(" | MaxCars -> ") + std::to_string(MaxCars));
info(Name + (" | MaxCars -> ") + std::to_string(MaxCars));
} else
SendError(L, Sec("set invalid argument [2] expected number for ID : 2"));
SendError(L, ("set invalid argument [2] expected number for ID : 2"));
break;
case 3: //max players
if (lua_isnumber(L, 2)) {
MaxPlayers = int(lua_tointeger(L, 2));
info(Name + Sec(" | MaxPlayers -> ") + std::to_string(MaxPlayers));
info(Name + (" | MaxPlayers -> ") + std::to_string(MaxPlayers));
} else
SendError(L, Sec("set invalid argument [2] expected number for ID : 3"));
SendError(L, ("set invalid argument [2] expected number for ID : 3"));
break;
case 4: //Map
if (lua_isstring(L, 2)) {
MapName = lua_tostring(L, 2);
info(Name + Sec(" | MapName -> ") + MapName);
info(Name + (" | MapName -> ") + MapName);
} else
SendError(L, Sec("set invalid argument [2] expected string for ID : 4"));
SendError(L, ("set invalid argument [2] expected string for ID : 4"));
break;
case 5: //Name
if (lua_isstring(L, 2)) {
ServerName = lua_tostring(L, 2);
info(Name + Sec(" | ServerName -> ") + ServerName);
info(Name + (" | ServerName -> ") + ServerName);
} else
SendError(L, Sec("set invalid argument [2] expected string for ID : 5"));
SendError(L, ("set invalid argument [2] expected string for ID : 5"));
break;
case 6: //Desc
if (lua_isstring(L, 2)) {
ServerDesc = lua_tostring(L, 2);
info(Name + Sec(" | ServerDesc -> ") + ServerDesc);
info(Name + (" | ServerDesc -> ") + ServerDesc);
} else
SendError(L, Sec("set invalid argument [2] expected string for ID : 6"));
SendError(L, ("set invalid argument [2] expected string for ID : 6"));
break;
default:
warn(Sec("Invalid config ID : ") + std::to_string(C));
warn(("Invalid config ID : ") + std::to_string(C));
break;
}
@@ -522,9 +541,9 @@ int lua_Print(lua_State* L) {
for (int i = 1; i <= Arg; i++) {
auto str = lua_tostring(L, i);
if (str != nullptr) {
ConsoleOut(str + std::string(Sec("\n")));
ConsoleOut(str + std::string(("\n")));
} else {
ConsoleOut(Sec("nil\n"));
ConsoleOut(("nil\n"));
}
}
return 0;
@@ -556,14 +575,14 @@ void Lua::Execute(const std::string& Command) {
}
void Lua::Reload() {
if (CheckLua(luaState, luaL_dofile(luaState, _FileName.c_str()))) {
CallFunction(this, Sec("onInit"), nullptr);
CallFunction(this, ("onInit"), nullptr);
}
}
std::string Lua::GetOrigin() {
return fs::path(GetFileName()).filename().string();
}
int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> Arg) {
std::any CallFunction(Lua* lua, const std::string& FuncName, std::shared_ptr<LuaArg> Arg) {
lua_State* luaState = lua->GetState();
lua_getglobal(luaState, FuncName.c_str());
if (lua_isfunction(luaState, -1)) {
@@ -572,11 +591,12 @@ int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg>
Size = int(Arg->args.size());
Arg->PushArgs(luaState);
}
std::string Origin = lua->GetOrigin();
int R = lua_pcall(luaState, Size, 1, 0);
if (CheckLua(luaState, R)) {
if (lua_isnumber(luaState, -1)) {
return int(lua_tointeger(luaState, -1));
} else if (lua_isstring(luaState, -1)) {
return std::string(lua_tostring(luaState, -1));
}
}
}
@@ -589,6 +609,22 @@ void Lua::SetPluginName(const std::string& Name) {
void Lua::SetFileName(const std::string& Name) {
_FileName = Name;
}
int lua_TempFix(lua_State* L) {
if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1));
Client* c = GetClient(ID);
if (c == nullptr)
return 0;
std::string Ret;
if (c->isGuest) {
Ret = "Guest-" + c->GetName();
} else
Ret = c->GetName();
lua_pushstring(L, Ret.c_str());
} else
SendError(L, "GetDID not enough arguments");
return 1;
}
void Lua::Init() {
Assert(luaState);
luaL_openlibs(luaState);
@@ -600,11 +636,12 @@ void Lua::Init() {
lua_register(luaState, "RegisterEvent", lua_RegisterEvent);
lua_register(luaState, "GetPlayerName", lua_GetPlayerName);
lua_register(luaState, "RemoveVehicle", lua_RemoveVehicle);
lua_register(luaState, "GetPlayerDiscordID", lua_GetDID);
lua_register(luaState, "GetPlayerVehicles", lua_GetCars);
lua_register(luaState, "GetPlayerDiscordID", lua_TempFix);
lua_register(luaState, "CreateThread", lua_CreateThread);
lua_register(luaState, "GetPlayerVehicles", lua_GetCars);
lua_register(luaState, "SendChatMessage", lua_sendChat);
lua_register(luaState, "GetPlayers", lua_GetAllPlayers);
lua_register(luaState, "GetPlayerGuest", lua_GetGuest);
lua_register(luaState, "StopThread", lua_StopThread);
lua_register(luaState, "DropPlayer", lua_dropPlayer);
lua_register(luaState, "GetPlayerHWID", lua_HWID);

View File

@@ -1,233 +1,143 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/31/2020
///
#include "Curl/Http.h"
#include "Json.h"
#include "Logger.h"
#include "Network.h"
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <algorithm>
#include <atomic>
#include <Lua/LuaSystem.hpp>
#include <cstring>
#include <sstream>
#include <string>
#include <thread>
bool Send(SOCKET TCPSock, std::string Data) {
#ifdef WIN32
int BytesSent;
int len = static_cast<int>(Data.size());
#else
int64_t BytesSent;
size_t len = Data.size();
#endif // WIN32
BytesSent = send(TCPSock, Data.c_str(), len, 0);
Data.clear();
if (BytesSent <= 0) {
#ifndef WIN32
error(__func__ + std::string(" ") + strerror(errno));
#else
error(__func__ + std::string(" ") + std::to_string(WSAGetLastError()));
#endif // WIN32
return false;
}
return true;
}
std::string Rcv(SOCKET TCPSock) {
uint32_t RealSize;
#ifdef WIN32
int64_t BytesRcv = recv(TCPSock, reinterpret_cast<char*>(&RealSize), sizeof(RealSize), 0);
#else
int64_t BytesRcv = recv(TCPSock, reinterpret_cast<void*>(&RealSize), sizeof(RealSize), 0);
#endif
if (BytesRcv != sizeof(RealSize)) {
error(std::string(Sec("invalid packet: expected 4, got ")) + std::to_string(BytesRcv));
return "";
}
// RealSize is big-endian, so we convert it to host endianness
RealSize = ntohl(RealSize);
debug(std::string("got ") + std::to_string(RealSize) + " as size");
if (RealSize > 7000) {
error(Sec("Larger than allowed TCP packet received"));
return "";
}
char buf[7000];
std::fill_n(buf, 7000, 0);
BytesRcv = recv(TCPSock, buf, RealSize, 0);
if (BytesRcv != RealSize) {
debug("expected " + std::to_string(RealSize) + " bytes, got " + std::to_string(BytesRcv) + " instead");
}
if (BytesRcv <= 0)
return "";
return std::string(buf);
}
std::string GetRole(const std::string& DID) {
if (!DID.empty()) {
std::string a = HttpRequest(Sec("https://beammp.com/entitlement?did=") + DID, 443);
std::string b = HttpRequest(Sec("https://backup1.beammp.com/entitlement?did=") + DID, 443);
if (!a.empty() || !b.empty()) {
if (a != b)
a = b;
auto pos = a.find('"');
if (pos != std::string::npos) {
return a.substr(pos + 1, a.find('"', pos + 1) - 2);
} else if (a == "[]")
return Sec("Member");
}
std::string GetClientInfo(const std::string& PK) {
if (!PK.empty()) {
return PostHTTP("https://auth.beammp.com/pkToUser", R"({"key":")" + PK + "\"}", true);
;
}
return "";
}
void Check(SOCKET TCPSock, std::shared_ptr<std::atomic_bool> ok) {
DebugPrintTID();
size_t accum = 0;
while (!*ok) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
accum += 100;
if (accum >= 5000) {
error(Sec("Identification timed out (Check accum)"));
CloseSocketProper(TCPSock);
return;
}
}
}
int Max() {
int M = MaxPlayers;
for (auto& c : CI->Clients) {
if (c != nullptr) {
if (c->GetRole() == Sec("MDEV"))
M++;
}
}
return M;
}
void CreateClient(SOCKET TCPSock, const std::string& Name, const std::string& DID, const std::string& Role) {
Client* CreateClient(SOCKET TCPSock) {
auto* c = new Client;
c->SetTCPSock(TCPSock);
c->SetName(Name);
c->SetRole(Role);
c->SetDID(DID);
Client& Client = *c;
CI->AddClient(std::move(c));
InitClient(&Client);
}
std::pair<int, int> Parse(const std::string& msg) {
std::stringstream ss(msg);
std::string t;
std::pair<int, int> a = { 0, 0 }; //N then E
while (std::getline(ss, t, 'g')) {
if (t.find_first_not_of(Sec("0123456789abcdef")) != std::string::npos)
return a;
if (a.first == 0) {
a.first = std::stoi(t, nullptr, 16);
} else if (a.second == 0) {
a.second = std::stoi(t, nullptr, 16);
} else
return a;
}
return { 0, 0 };
}
std::string GenerateM(RSA* key) {
std::stringstream stream;
stream << std::hex << key->n << "g" << key->e << "g" << RSA_E(Sec("IDC"), key);
return stream.str();
return c;
}
void Identification(SOCKET TCPSock, RSA* Skey) {
void ClientKick(Client* c, const std::string& R) {
info("Client kicked: " + R);
TCPSend(c, "E" + R);
CloseSocketProper(c->GetTCPSock());
}
void Authentication(SOCKET TCPSock) {
DebugPrintTID();
Assert(Skey);
std::shared_ptr<std::atomic_bool> ok = std::make_shared<std::atomic_bool>(false);
std::thread Timeout(Check, TCPSock, ok);
Timeout.detach();
std::string Name, DID, Role;
if (!Send(TCPSock, GenerateM(Skey))) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
return;
}
std::string msg = Rcv(TCPSock);
auto Keys = Parse(msg);
if (!Send(TCPSock, RSA_E("HC", Keys.second, Keys.first))) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
return;
}
auto* c = CreateClient(TCPSock);
std::string Res = Rcv(TCPSock);
std::string Ver = Rcv(TCPSock);
*ok = true;
Ver = RSA_D(Ver, Skey);
if (Ver.size() > 3 && Ver.substr(0, 2) == Sec("VC")) {
Ver = Ver.substr(2);
if (Ver.length() > 4 || Ver != GetCVer()) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
info("Identifying new client...");
std::string Rc = TCPRcv(c);
if (Rc.size() > 3 && Rc.substr(0, 2) == "VC") {
Rc = Rc.substr(2);
if (Rc.length() > 4 || Rc != GetCVer()) {
ClientKick(c, "Outdated Version!");
return;
}
} else {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
ClientKick(c, "Invalid version header!");
return;
}
Res = RSA_D(Res, Skey);
if (Res.size() < 3 || Res.substr(0, 2) != Sec("NR")) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
TCPSend(c, "S");
Rc = TCPRcv(c);
if (Rc.size() > 50) {
ClientKick(c, "Invalid Key!");
return;
}
if (Res.find(':') == std::string::npos) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
Rc = GetClientInfo(Rc);
json::Document d;
d.Parse(Rc.c_str());
if (Rc == "-1" || d.HasParseError()) {
ClientKick(c, "Invalid key! Please restart your game.");
return;
}
Name = Res.substr(2, Res.find(':') - 2);
DID = Res.substr(Res.find(':') + 1);
Role = GetRole(DID);
if (Role.empty() || Role.find(Sec("Error")) != std::string::npos) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
if (d["username"].IsString() && d["roles"].IsString() && d["guest"].IsBool()) {
c->SetName(d["username"].GetString());
c->SetRoles(d["roles"].GetString());
c->isGuest = d["guest"].GetBool();
} else {
ClientKick(c, "Invalid authentication data!");
return;
}
// DebugPrintTIDInternal(std::string("Client(") + Name + ")");
debug(Sec("Name -> ") + Name + Sec(", Role -> ") + Role + Sec(", ID -> ") + DID);
for (auto& c : CI->Clients) {
if (c != nullptr) {
if (c->GetDID() == DID) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(c->GetTCPSock());
c->SetStatus(-2);
debug("Name -> " + c->GetName() + ", Guest -> " + std::to_string(c->isGuest) + ", Roles -> " + c->GetRoles());
for (auto& Cl : CI->Clients) {
if (Cl != nullptr) {
if (Cl->GetName() == c->GetName() && Cl->isGuest == c->isGuest) {
info("Old client (" + Cl->GetName() + ") kicked: Reconnecting");
CloseSocketProper(Cl->GetTCPSock());
Cl->SetStatus(-2);
break;
}
}
}
if (Role == Sec("MDEV") || CI->Size() < Max()) {
debug("Identification success");
CreateClient(TCPSock, Name, DID, Role);
} else {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
auto arg = std::make_unique<LuaArg>(LuaArg { { c->GetName(), c->GetRoles(), c->isGuest } });
std::any Res = TriggerLuaEvent("onPlayerAuth", false, nullptr, std::move(arg), true);
std::string Type = Res.type().name();
if (Type.find("int") != std::string::npos && std::any_cast<int>(Res)) {
ClientKick(c, "you are not allowed on the server!");
return;
} else if (Type.find("string") != std::string::npos) {
ClientKick(c, std::any_cast<std::string>(Res));
return;
}
if (CI->Size() < MaxPlayers) {
info("Identification success");
Client& Client = *c;
CI->AddClient(std::move(c));
TCPClient(&Client);
} else
ClientKick(c, "Server full!");
}
void Identify(SOCKET TCPSock) {
RSA* Skey = GenKey();
// this disgusting ifdef stuff is needed because for some
// reason MSVC defines __try and __except and libg++ defines
// __try and __catch so its all a big mess if we leave this in or undefine
// the macros
/*#ifdef WIN32
__try{
#endif // WIN32*/
Identification(TCPSock, Skey);
/*#ifdef WIN32
}__except(1){
if(TCPSock != -1){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(TCPSock);
void HandleDownload(SOCKET TCPSock) {
char D;
if (recv(TCPSock, &D, 1, 0) != 1) {
CloseSocketProper(TCPSock);
return;
}
auto ID = uint8_t(D);
for (auto& c : CI->Clients) {
if (c->GetID() == ID) {
c->SetDownSock(TCPSock);
}
}
#endif // WIN32*/
}
delete Skey;
void Identify(SOCKET TCPSock) {
char Code;
if (recv(TCPSock, &Code, 1, 0) != 1) {
CloseSocketProper(TCPSock);
return;
}
if (Code == 'C') {
Authentication(TCPSock);
} else if (Code == 'D') {
HandleDownload(TCPSock);
} else
CloseSocketProper(TCPSock);
}
void TCPServerMain() {
@@ -235,7 +145,7 @@ void TCPServerMain() {
#ifdef WIN32
WSADATA wsaData;
if (WSAStartup(514, &wsaData)) {
error(Sec("Can't start Winsock!"));
error("Can't start Winsock!");
return;
}
SOCKET client, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -244,30 +154,30 @@ void TCPServerMain() {
addr.sin_family = AF_INET;
addr.sin_port = htons(Port);
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
error(Sec("Can't bind socket! ") + std::to_string(WSAGetLastError()));
error("Can't bind socket! " + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5));
_Exit(-1);
}
if (Listener == -1) {
error(Sec("Invalid listening socket"));
error("Invalid listening socket");
return;
}
if (listen(Listener, SOMAXCONN)) {
error(Sec("listener failed ") + std::to_string(GetLastError()));
error("listener failed " + std::to_string(GetLastError()));
return;
}
info(Sec("Vehicle event network online"));
info("Vehicle event network online");
do {
try {
client = accept(Listener, nullptr, nullptr);
if (client == -1) {
warn(Sec("Got an invalid client socket on connect! Skipping..."));
warn("Got an invalid client socket on connect! Skipping...");
continue;
}
std::thread ID(Identify, client);
ID.detach();
} catch (const std::exception& e) {
error(Sec("fatal: ") + std::string(e.what()));
error("fatal: " + std::string(e.what()));
}
} while (client);
@@ -285,30 +195,30 @@ void TCPServerMain() {
addr.sin_family = AF_INET;
addr.sin_port = htons(uint16_t(Port));
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) {
error(Sec("Can't bind socket! ") + std::string(strerror(errno)));
error(("Can't bind socket! ") + std::string(strerror(errno)));
std::this_thread::sleep_for(std::chrono::seconds(5));
_Exit(-1);
}
if (Listener == -1) {
error(Sec("Invalid listening socket"));
error(("Invalid listening socket"));
return;
}
if (listen(Listener, SOMAXCONN)) {
error(Sec("listener failed ") + std::string(strerror(errno)));
error(("listener failed ") + std::string(strerror(errno)));
return;
}
info(Sec("Vehicle event network online"));
info(("Vehicle event network online"));
do {
try {
client = accept(Listener, nullptr, nullptr);
if (client == -1) {
warn(Sec("Got an invalid client socket on connect! Skipping..."));
warn(("Got an invalid client socket on connect! Skipping..."));
continue;
}
std::thread ID(Identify, client);
ID.detach();
} catch (const std::exception& e) {
error(Sec("fatal: ") + std::string(e.what()));
error(("fatal: ") + std::string(e.what()));
}
} while (client);

View File

@@ -1,50 +1,14 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/8/2020
///
#include "Client.hpp"
std::string Client::GetName() {
return Name;
}
void Client::SetName(const std::string& name) {
Name = name;
}
void Client::SetDID(const std::string& did) {
DID = did;
}
std::string Client::GetDID() {
return DID;
}
void Client::SetRole(const std::string& role) {
Role = role;
}
std::string Client::GetRole() {
return Role;
}
int Client::GetID() {
return ID;
}
void Client::SetID(int id) {
ID = id;
}
void Client::SetStatus(int state) {
Status = state;
}
int Client::GetStatus() {
return Status;
}
void Client::SetUDPAddr(sockaddr_in Addr) {
UDPADDR = Addr;
}
sockaddr_in Client::GetUDPAddr() {
return UDPADDR;
}
void Client::SetTCPSock(SOCKET CSock) {
TCPSOCK = CSock;
}
SOCKET Client::GetTCPSock() {
return TCPSOCK;
}
#include <memory>
void Client::DeleteCar(int ident) {
for (auto& v : VehicleData) {
if (v != nullptr && v->ID == ident) {
@@ -71,17 +35,13 @@ int Client::GetOpenCarID() {
return OpenID;
}
void Client::AddNewCar(int ident, const std::string& Data) {
VehicleData.insert(std::unique_ptr<VData>(new VData { ident, Data }));
VehicleData.insert(std::make_unique<VData>(VData { ident, Data }));
}
std::set<std::unique_ptr<VData>>& Client::GetAllCars() {
return VehicleData;
}
const std::set<std::unique_ptr<VData>>& Client::GetAllCars() const {
return VehicleData;
}
std::string Client::GetCarData(int ident) {
for (auto& v : VehicleData) {
if (v != nullptr && v->ID == ident) {
@@ -91,6 +51,7 @@ std::string Client::GetCarData(int ident) {
DeleteCar(ident);
return "";
}
void Client::SetCarData(int ident, const std::string& Data) {
for (auto& v : VehicleData) {
if (v != nullptr && v->ID == ident) {

View File

@@ -1,6 +1,11 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Client.hpp"
#include "Logger.h"
#include "Lua/LuaSystem.hpp"
@@ -8,27 +13,37 @@
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <memory>
#include <sstream>
#undef GetObject //to fix microsoft bs
#include "Json.h"
int FC(const std::string& s, const std::string& p, int n) {
auto i = s.find(p);
int j;
for (j = 1; j < n && i != std::string::npos; ++j) {
i = s.find(p, i + 1);
}
if (j == n)
return int(i);
else
return -1;
}
void Apply(Client* c, int VID, const std::string& pckt) {
Assert(c);
std::string Packet = pckt;
std::string VD = c->GetCarData(VID);
Packet = Packet.substr(FC(Packet, ",", 2) + 1);
Packet = VD.substr(0, FC(VD, ",", 2) + 1) + Packet.substr(0, Packet.find_last_of('"') + 1) + VD.substr(FC(VD, ",\"", 7));
c->SetCarData(VID, Packet);
std::string Packet = pckt.substr(pckt.find('{')), VD = c->GetCarData(VID);
std::string Header = VD.substr(0, VD.find('{'));
VD = VD.substr(VD.find('{'));
rapidjson::Document Veh, Pack;
Veh.Parse(VD.c_str());
if (Veh.HasParseError()) {
error("Could not get vehicle config!");
return;
}
Pack.Parse(Packet.c_str());
if (Pack.HasParseError() || Pack.IsNull()) {
error("Could not get active vehicle config!");
return;
}
for (auto& M : Pack.GetObject()) {
if (Veh[M.name].IsNull()) {
Veh.AddMember(M.name, M.value, Veh.GetAllocator());
} else {
Veh[M.name] = Pack[M.name];
}
}
rapidjson::StringBuffer Buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(Buffer);
Veh.Accept(writer);
c->SetCarData(VID, Header + Buffer.GetString());
}
void VehicleParser(Client* c, const std::string& Pckt) {
@@ -43,17 +58,18 @@ void VehicleParser(Client* c, const std::string& Pckt) {
switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset
case 's':
#ifdef DEBUG
debug(std::string(Sec("got 'Os' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
if (Data.at(0) == '0') {
int CarID = c->GetOpenCarID();
debug(c->GetName() + Sec(" created a car with ID ") + std::to_string(CarID));
Packet = "Os:" + c->GetRole() + ":" + c->GetName() + ":" + std::to_string(c->GetID()) + "-" + std::to_string(CarID) + Packet.substr(4);
if (c->GetCarCount() >= MaxCars || TriggerLuaEvent(Sec("onVehicleSpawn"), false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID(), CarID, Packet.substr(3) } }), true)) {
debug(c->GetName() + (" created a car with ID ") + std::to_string(CarID));
Packet = "Os:" + c->GetRoles() + ":" + c->GetName() + ":" + std::to_string(c->GetID()) + "-" + std::to_string(CarID) + Packet.substr(4);
auto Res = TriggerLuaEvent(("onVehicleSpawn"), false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID(), CarID, Packet.substr(3) } }), true);
if (c->GetCarCount() >= MaxCars || std::any_cast<int>(Res)) {
Respond(c, Packet, true);
std::string Destroy = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(CarID);
Respond(c, Destroy, true);
debug(c->GetName() + Sec(" (force : car limit/lua) removed ID ") + std::to_string(CarID));
debug(c->GetName() + (" (force : car limit/lua) removed ID ") + std::to_string(CarID));
} else {
c->AddNewCar(CarID, Packet);
SendToAll(nullptr, Packet, true, true);
@@ -62,7 +78,7 @@ void VehicleParser(Client* c, const std::string& Pckt) {
return;
case 'c':
#ifdef DEBUG
debug(std::string(Sec("got 'Oc' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'Oc' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
pid = Data.substr(0, Data.find('-'));
vid = Data.substr(Data.find('-') + 1, Data.find(':', 1) - Data.find('-') - 1);
@@ -71,9 +87,10 @@ void VehicleParser(Client* c, const std::string& Pckt) {
VID = stoi(vid);
}
if (PID != -1 && VID != -1 && PID == c->GetID()) {
if (!TriggerLuaEvent(Sec("onVehicleEdited"), false, nullptr,
std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), VID, Packet.substr(3) } }),
true)) {
auto Res = TriggerLuaEvent(("onVehicleEdited"), false, nullptr,
std::make_unique<LuaArg>(LuaArg { { c->GetID(), VID, Packet.substr(3) } }),
true);
if (!std::any_cast<int>(Res)) {
SendToAll(c, Packet, false, true);
Apply(c, VID, Packet);
} else {
@@ -85,7 +102,7 @@ void VehicleParser(Client* c, const std::string& Pckt) {
return;
case 'd':
#ifdef DEBUG
debug(std::string(Sec("got 'Od' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'Od' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
pid = Data.substr(0, Data.find('-'));
vid = Data.substr(Data.find('-') + 1);
@@ -95,21 +112,27 @@ void VehicleParser(Client* c, const std::string& Pckt) {
}
if (PID != -1 && VID != -1 && PID == c->GetID()) {
SendToAll(nullptr, Packet, true, true);
TriggerLuaEvent(Sec("onVehicleDeleted"), false, nullptr,
std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), VID } }), false);
TriggerLuaEvent(("onVehicleDeleted"), false, nullptr,
std::make_unique<LuaArg>(LuaArg { { c->GetID(), VID } }), false);
c->DeleteCar(VID);
debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID));
debug(c->GetName() + (" deleted car with ID ") + std::to_string(VID));
}
return;
case 'r':
#ifdef DEBUG
debug(std::string(Sec("got 'Or' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'Or' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
SendToAll(c, Packet, false, true);
return;
case 't':
#ifdef DEBUG
debug(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
SendToAll(c, Packet, false, true);
return;
default:
#ifdef DEBUG
warn(std::string(Sec("possibly not implemented: '") + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")")));
warn(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")")));
#endif // DEBUG
return;
}
@@ -120,15 +143,16 @@ void SyncClient(Client* c) {
return;
c->isSynced = true;
std::this_thread::sleep_for(std::chrono::seconds(1));
Respond(c, Sec("Sn") + c->GetName(), true);
SendToAll(c, Sec("JWelcome ") + c->GetName() + "!", false, true);
TriggerLuaEvent(Sec("onPlayerJoin"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
Respond(c, ("Sn") + c->GetName(), true);
SendToAll(c, ("JWelcome ") + c->GetName() + "!", false, true);
TriggerLuaEvent(("onPlayerJoin"), false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID() } }), false);
for (auto& client : CI->Clients) {
if (client != nullptr) {
if (client.get() != c) {
for (auto& v : client->GetAllCars()) {
if (v != nullptr) {
if(c->GetStatus() < 0)return;
if (c->GetStatus() < 0)
return;
Respond(c, v->Data, true);
std::this_thread::sleep_for(std::chrono::seconds(2));
}
@@ -136,14 +160,14 @@ void SyncClient(Client* c) {
}
}
}
info(c->GetName() + Sec(" is now synced!"));
info(c->GetName() + (" is now synced!"));
}
void ParseVeh(Client* c, const std::string& Packet) {
Assert(c);
#ifdef WIN32
__try {
VehicleParser(c, Packet);
} __except (Handle(GetExceptionInformation(), Sec("Vehicle Handler"))) { }
} __except (Handle(GetExceptionInformation(), ("Vehicle Handler"))) { }
#else // unix
VehicleParser(c, Packet);
#endif // WIN32
@@ -160,7 +184,7 @@ void HandleEvent(Client* c, const std::string& Data) {
Name = t;
break;
case 2:
TriggerLuaEvent(Name, false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), t } }), false);
TriggerLuaEvent(Name, false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID(), t } }), false);
break;
default:
break;
@@ -171,12 +195,11 @@ void HandleEvent(Client* c, const std::string& Data) {
}
}
void GlobalParser(Client* c, const std::string& Pack) {
void GlobalParser(Client* c, const std::string& Packet) {
Assert(c);
if (Pack.empty() || c == nullptr)
if (Packet.empty() || c == nullptr)
return;
std::string Packet = Pack.substr(0, strlen(Pack.c_str()));
std::string pct;
std::any Res;
char Code = Packet.at(0);
//V to Z
@@ -186,45 +209,42 @@ void GlobalParser(Client* c, const std::string& Pack) {
return;
}
switch (Code) {
case 'P': // initial connection
case 'H': // initial connection
#ifdef DEBUG
debug(std::string(Sec("got 'P' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")");
#endif
Respond(c, Sec("P") + std::to_string(c->GetID()), true);
SyncClient(c);
return;
case 'p':
Respond(c, Sec("p"), false);
Respond(c, ("p"), false);
UpdatePlayers();
return;
case 'O':
if (Packet.length() > 1000) {
debug(Sec("Received data from: ") + c->GetName() + Sec(" Size: ") + std::to_string(Packet.length()));
debug(("Received data from: ") + c->GetName() + (" Size: ") + std::to_string(Packet.length()));
}
ParseVeh(c, Packet);
return;
case 'J':
#ifdef DEBUG
debug(std::string(Sec("got 'J' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
SendToAll(c, Packet, false, true);
return;
case 'C':
#ifdef DEBUG
debug(std::string(Sec("got 'C' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos)
break;
if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,
std::unique_ptr<LuaArg>(new LuaArg {
{ c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }),
true))
Res = TriggerLuaEvent("onChatMessage", false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }), true);
if (std::any_cast<int>(Res))
break;
SendToAll(nullptr, Packet, true, true);
return;
case 'E':
#ifdef DEBUG
debug(std::string(Sec("got 'E' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
#endif
HandleEvent(c, Packet);
return;
@@ -241,7 +261,7 @@ void GParser(Client* c, const std::string& Packet) {
#ifdef WIN32
__try {
GlobalParser(c, Packet);
} __except (Handle(GetExceptionInformation(), Sec("Global Handler"))) { }
} __except (Handle(GetExceptionInformation(), ("Global Handler"))) { }
#else
GlobalParser(c, Packet);
#endif // WIN32

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 4/9/2020
///
@@ -5,15 +9,31 @@
#include "CustomAssert.h"
#include <curl/curl.h>
#include <iostream>
class CurlManager{
public:
CurlManager(){
curl = curl_easy_init();
}
~CurlManager(){
curl_easy_cleanup(curl);
}
inline CURL* Get(){
return curl;
}
private:
CURL *curl;
};
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
std::string HttpRequest(const std::string& IP, int port) {
CURL* curl;
CURLcode res;
static thread_local CurlManager M;
std::string readBuffer;
curl = curl_easy_init();
CURL* curl = M.Get();
CURLcode res;
Assert(curl);
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
@@ -21,30 +41,33 @@ std::string HttpRequest(const std::string& IP, int port) {
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK)
return "-1";
}
return readBuffer;
}
std::string PostHTTP(const std::string& IP, const std::string& Fields) {
CURL* curl;
std::string PostHTTP(const std::string& IP, const std::string& Fields, bool json) {
auto header = curl_slist { (char*)"Content-Type: application/json" };
static thread_local CurlManager M;
static std::mutex Lock;
std::scoped_lock Guard(Lock);
CURL* curl = M.Get();
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
Assert(curl);
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
/*curl_easy_setopt(curl, CURLOPT_URL, "https://95.216.35.232/heartbeatv2");
curl_easy_setopt(curl, CURLOPT_PORT, 3600);*/
if (json)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK)
return "-1";
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 8/1/2020
///
@@ -5,8 +9,10 @@
#include "Logger.h"
#include "Lua/LuaSystem.hpp"
#include "Network.h"
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <memory>
int OpenID() {
int ID = 0;
bool found;
@@ -57,7 +63,7 @@ void SendToAll(Client* c, const std::string& Data, bool Self, bool Rel) {
}
}
void UpdatePlayers() {
std::string Packet = Sec("Ss") + std::to_string(CI->Size()) + "/" + std::to_string(MaxPlayers) + ":";
std::string Packet = ("Ss") + std::to_string(CI->Size()) + "/" + std::to_string(MaxPlayers) + ":";
for (auto& c : CI->Clients) {
if (c != nullptr)
Packet += c->GetName() + ",";
@@ -66,11 +72,8 @@ void UpdatePlayers() {
SendToAll(nullptr, Packet, true, true);
}
void OnDisconnect(Client* c, bool kicked) {
Assert(c);
info(c->GetName() + Sec(" Connection Terminated"));
if (c == nullptr)
return;
info(c->GetName() + (" Connection Terminated"));
std::string Packet;
for (auto& v : c->GetAllCars()) {
if (v != nullptr) {
@@ -79,23 +82,28 @@ void OnDisconnect(Client* c, bool kicked) {
}
}
if (kicked)
Packet = Sec("L") + c->GetName() + Sec(" was kicked!");
Packet = Sec("L") + c->GetName() + Sec(" Left the server!");
Packet = ("L") + c->GetName() + (" was kicked!");
else
Packet = ("L") + c->GetName() + (" left the server!");
SendToAll(c, Packet, false, true);
Packet.clear();
TriggerLuaEvent(Sec("onPlayerDisconnect"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
CI->RemoveClient(c); ///Removes the Client from existence
TriggerLuaEvent(("onPlayerDisconnect"), false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID() } }), false);
if (c->GetTCPSock())
CloseSocketProper(c->GetTCPSock());
if (c->GetDownSock())
CloseSocketProper(c->GetDownSock());
CI->RemoveClient(c);
}
void OnConnect(Client* c) {
Assert(c);
info(Sec("Client connected"));
info("Client connected");
c->SetID(OpenID());
info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName());
TriggerLuaEvent(Sec("onPlayerConnecting"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
info("Assigned ID " + std::to_string(c->GetID()) + " to " + c->GetName());
TriggerLuaEvent("onPlayerConnecting", false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID() } }), false);
SyncResources(c);
if (c->GetStatus() < 0)
return;
Respond(c, "M" + MapName, true); //Send the Map on connect
info(c->GetName() + Sec(" : Connected"));
TriggerLuaEvent(Sec("onPlayerJoining"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
info(c->GetName() + " : Connected");
TriggerLuaEvent("onPlayerJoining", false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID() } }), false);
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 6/18/2020
///
@@ -9,7 +13,7 @@
std::string StatReport;
int PPS = 0;
void Monitor() {
int R, C = 0, V = 0;
int C = 0, V = 0;
if (CI->Clients.empty()) {
StatReport = "-";
return;
@@ -23,7 +27,7 @@ void Monitor() {
if (C == 0 || PPS == 0) {
StatReport = "-";
} else {
R = (PPS / C) / V;
int R = (PPS / C) / V;
StatReport = std::to_string(R);
}
PPS = 0;

View File

@@ -1,75 +1,110 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Client.hpp"
#include "Logger.h"
#include "Network.h"
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <filesystem>
#include <fstream>
#ifdef __linux
// we need this for `struct stat`
#include <sys/stat.h>
#endif // __linux
void STCPSend(Client* c, std::string Data) {
Assert(c);
if (c == nullptr)
return;
#ifdef WIN32
int BytesSent;
int len = static_cast<int>(Data.size());
#else
int64_t BytesSent;
size_t len = Data.size();
#endif // WIN32
BytesSent = send(c->GetTCPSock(), Data.c_str(), len, 0);
Data.clear();
if (BytesSent == 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
} else if (BytesSent < 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
info(Sec("Closing socket, BytesSent < 0"));
CloseSocketProper(c->GetTCPSock());
}
bool TCPSendRaw(SOCKET C, char* Data, int32_t Size) {
int64_t Sent = 0;
do {
int64_t Temp = send(C, &Data[Sent], int(Size - Sent), 0);
if (Temp < 1) {
info("Socket Closed! " + std::to_string(C));
CloseSocketProper(C);
return false;
}
Sent += Temp;
} while (Sent < Size);
return true;
}
void SendFile(Client* c, const std::string& Name) {
Assert(c);
info(c->GetName() + Sec(" requesting : ") + Name.substr(Name.find_last_of('/')));
struct stat Info { };
if (stat(Name.c_str(), &Info) != 0) {
STCPSend(c, Sec("Cannot Open"));
return;
}
void SplitLoad(Client* c, int64_t Sent, int64_t Size, bool D, const std::string& Name) {
std::ifstream f(Name.c_str(), std::ios::binary);
f.seekg(0, std::ios_base::end);
std::streampos fileSize = f.tellg();
size_t Size = size_t(fileSize);
size_t Sent = 0;
size_t Diff;
int64_t Split = 64000;
int32_t Split = 0x7735940; //125MB
char* Data;
if (Size > Split)
Data = new char[Split];
else
Data = new char[Size];
SOCKET TCPSock;
if (D)
TCPSock = c->GetDownSock();
else
TCPSock = c->GetTCPSock();
info("Split load Socket " + std::to_string(TCPSock));
while (c->GetStatus() > -1 && Sent < Size) {
Diff = Size - Sent;
if (Diff > size_t(Split)) {
std::string Data(size_t(Split), 0);
f.seekg(int64_t(Sent), std::ios_base::beg);
f.read(&Data[0], Split);
STCPSend(c, Data);
Sent += size_t(Split);
int64_t Diff = Size - Sent;
if (Diff > Split) {
f.seekg(Sent, std::ios_base::beg);
f.read(Data, Split);
if (!TCPSendRaw(TCPSock, Data, Split)) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
break;
}
Sent += Split;
} else {
std::string Data(Diff, 0);
f.seekg(int64_t(Sent), std::ios_base::beg);
f.read(&Data[0], int64_t(Diff));
STCPSend(c, Data);
f.seekg(Sent, std::ios_base::beg);
f.read(Data, Diff);
if (!TCPSendRaw(TCPSock, Data, int32_t(Diff))) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
break;
}
Sent += Diff;
}
}
delete[] Data;
f.close();
}
void SendFile(Client* c, const std::string& Name) {
Assert(c);
info(c->GetName() + " requesting : " + Name.substr(Name.find_last_of('/')));
if (!std::filesystem::exists(Name)) {
TCPSend(c, "CO");
warn("File " + Name + " could not be accessed!");
return;
} else
TCPSend(c, "AG");
///Wait for connections
int T = 0;
while (c->GetDownSock() < 1 && T < 50) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
T++;
}
if (c->GetDownSock() < 1) {
error("Client doesn't have a download socket!");
if (c->GetStatus() > -1)
c->SetStatus(-1);
return;
}
int64_t Size = std::filesystem::file_size(Name), MSize = Size / 2;
std::thread Dt(SplitLoad, c, 0, MSize, false, Name);
Dt.detach();
SplitLoad(c, MSize, Size, true, Name);
if (Dt.joinable())
Dt.join();
}
void Parse(Client* c, const std::string& Packet) {
Assert(c);
if (c == nullptr || Packet.empty())
@@ -83,11 +118,11 @@ void Parse(Client* c, const std::string& Packet) {
return;
case 'S':
if (SubCode == 'R') {
debug(Sec("Sending Mod Info"));
debug("Sending Mod Info");
std::string ToSend = FileList + FileSizes;
if (ToSend.empty())
ToSend = "-";
STCPSend(c, ToSend);
TCPSend(c, ToSend);
}
return;
default:
@@ -95,45 +130,25 @@ void Parse(Client* c, const std::string& Packet) {
}
}
bool STCPRecv(Client* c) {
Assert(c);
if (c == nullptr)
return false;
#define len 200
char buf[len];
ZeroMemory(buf, len);
int64_t BytesRcv = recv(c->GetTCPSock(), buf, len, 0);
#undef len
if (BytesRcv == 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
info(Sec("Closing socket in STCP receive, BytesRcv == 0"));
CloseSocketProper(c->GetTCPSock());
return false;
} else if (BytesRcv < 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
info(Sec("Closing socket in STCP receive, BytesRcv < 0"));
CloseSocketProper(c->GetTCPSock());
return false;
}
if (strcmp(buf, "Done") == 0)
return false;
std::string Ret(buf, size_t(BytesRcv));
Parse(c, Ret);
return true;
}
void SyncResources(Client* c) {
Assert(c);
if (c == nullptr)
return;
#ifndef DEBUG
try {
STCPSend(c, Sec("WS"));
while (c->GetStatus() > -1 && STCPRecv(c))
;
#endif
TCPSend(c, "P" + std::to_string(c->GetID()));
std::string Data;
while (c->GetStatus() > -1) {
Data = TCPRcv(c);
if (Data == "Done")
break;
Parse(c, Data);
}
#ifndef DEBUG
} catch (std::exception& e) {
except(Sec("Exception! : ") + std::string(e.what()));
except("Exception! : " + std::string(e.what()));
c->SetStatus(-1);
}
#endif
}

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 8/1/2020
///
@@ -8,14 +12,12 @@
#include "UnixCompat.h"
#include <thread>
void TCPSend(Client* c, const std::string& Data) {
bool TCPSend(Client* c, const std::string& Data) {
Assert(c);
if (c == nullptr)
return;
// Size is BIG ENDIAN now, use only for header!
//auto Size = htonl(int32_t(Data.size()));
///TODO : BIG ENDIAN for other OS
int32_t Size, Sent, Temp;
return false;
int32_t Size, Sent;
std::string Send(4, 0);
Size = int32_t(Data.size());
memcpy(&Send[0], &Size, sizeof(Size));
@@ -23,71 +25,71 @@ void TCPSend(Client* c, const std::string& Data) {
Sent = 0;
Size += 4;
do {
Temp = send(c->GetTCPSock(), &Send[Sent], Size - Sent, 0);
int32_t Temp = send(c->GetTCPSock(), &Send[Sent], Size - Sent, 0);
if (Temp == 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
return;
return false;
} else if (Temp < 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
// info(Sec("Closing socket, Temp < 0"));
CloseSocketProper(c->GetTCPSock());
return;
return false;
}
Sent += Temp;
} while (Sent < Size);
return true;
}
bool CheckBytes(Client* c, int32_t BytesRcv) {
Assert(c);
if (BytesRcv == 0) {
debug(Sec("(TCP) Connection closing..."));
debug("(TCP) Connection closing...");
if (c->GetStatus() > -1)
c->SetStatus(-1);
return false;
} else if (BytesRcv < 0) {
#ifdef WIN32
debug(Sec("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
debug(("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
#else // unix
debug(Sec("(TCP) recv failed with error: ") + std::string(strerror(errno)));
debug(("(TCP) recv failed with error: ") + std::string(strerror(errno)));
#endif // WIN32
if (c->GetStatus() > -1)
c->SetStatus(-1);
info(Sec("Closing socket in CheckBytes, BytesRcv < 0"));
info(("Closing socket in CheckBytes, BytesRcv < 0"));
CloseSocketProper(c->GetTCPSock());
return false;
}
return true;
}
void TCPRcv(Client* c) {
std::string TCPRcv(Client* c) {
Assert(c);
int32_t Header, BytesRcv = 0, Temp;
if (c == nullptr || c->GetStatus() < 0)
return;
return "";
std::vector<char> Data(sizeof(Header));
do {
Temp = recv(c->GetTCPSock(), &Data[BytesRcv], 4 - BytesRcv, 0);
if (!CheckBytes(c, Temp)) {
#ifdef DEBUG
error(std::string(__func__) + Sec(": failed on CheckBytes in while(BytesRcv < 4)"));
error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < 4)"));
#endif // DEBUG
return;
return "";
}
BytesRcv += Temp;
} while (size_t(BytesRcv) < sizeof(Header));
memcpy(&Header, &Data[0], sizeof(Header));
#ifdef DEBUG
//debug(std::string(__func__) + Sec(": expecting ") + std::to_string(Header) + Sec(" bytes."));
//debug(std::string(__func__) + (": expecting ") + std::to_string(Header) + (" bytes."));
#endif // DEBUG
if (!CheckBytes(c, BytesRcv)) {
#ifdef DEBUG
error(std::string(__func__) + Sec(": failed on CheckBytes"));
error(std::string(__func__) + (": failed on CheckBytes"));
#endif // DEBUG
return;
return "";
}
Data.resize(Header);
BytesRcv = 0;
@@ -95,18 +97,18 @@ void TCPRcv(Client* c) {
Temp = recv(c->GetTCPSock(), &Data[BytesRcv], Header - BytesRcv, 0);
if (!CheckBytes(c, Temp)) {
#ifdef DEBUG
error(std::string(__func__) + Sec(": failed on CheckBytes in while(BytesRcv < Header)"));
error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < Header)"));
#endif // DEBUG
return;
return "";
}
#ifdef DEBUG
//debug(std::string(__func__) + Sec(": Temp: ") + std::to_string(Temp) + Sec(", BytesRcv: ") + std::to_string(BytesRcv));
//debug(std::string(__func__) + (": Temp: ") + std::to_string(Temp) + (", BytesRcv: ") + std::to_string(BytesRcv));
#endif // DEBUG
BytesRcv += Temp;
} while (BytesRcv < Header);
#ifdef DEBUG
//debug(std::string(__func__) + Sec(": finished recv with Temp: ") + std::to_string(Temp) + Sec(", BytesRcv: ") + std::to_string(BytesRcv));
//debug(std::string(__func__) + (": finished recv with Temp: ") + std::to_string(Temp) + (", BytesRcv: ") + std::to_string(BytesRcv));
#endif // DEBUG
std::string Ret(Data.data(), Header);
@@ -116,22 +118,20 @@ void TCPRcv(Client* c) {
#ifdef DEBUG
//debug("Parsing from " + c->GetName() + " -> " +std::to_string(Ret.size()));
#endif
GParser(c, Ret);
return Ret;
}
void TCPClient(Client* c) {
DebugPrintTIDInternal(Sec("Client(") + c->GetName() + Sec(")"), true);
DebugPrintTIDInternal("Client(" + c->GetName() + ")", true);
Assert(c);
if (c->GetTCPSock() == -1) {
CI->RemoveClient(c);
return;
}
OnConnect(c);
while (c->GetStatus() > -1)
TCPRcv(c);
while (c->GetStatus() > -1) {
GParser(c, TCPRcv(c));
}
OnDisconnect(c, c->GetStatus() == -2);
}
void InitClient(Client* c) {
std::thread NewClient(TCPClient, c);
NewClient.detach();
}

View File

@@ -1,7 +1,11 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 5/8/2020
///
///UDP
#include "Client.hpp"
#include "Compressor.h"
#include "Logger.h"
@@ -9,28 +13,14 @@
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <array>
#include <cmath>
#include <cstring>
#include <sstream>
#include <thread>
#include <vector>
int FC(const std::string& s, const std::string& p, int n);
struct PacketData {
int ID;
::Client* Client;
std::string Data;
int Tries;
};
struct SplitData {
int Total {};
int ID {};
std::set<std::pair<int, std::string>> Fragments;
};
#include <array>
SOCKET UDPSock;
std::set<PacketData*> DataAcks;
std::set<SplitData*> SplitPackets;
void UDPSend(Client* c, std::string Data) {
Assert(c);
if (c == nullptr || !c->isConnected || c->GetStatus() < 0)
@@ -52,51 +42,27 @@ void UDPSend(Client* c, std::string Data) {
sendOk = sendto(UDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, AddrSize);
#ifdef WIN32
if (sendOk == -1) {
debug(Sec("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
if (c->GetStatus() > -1)
c->SetStatus(-1);
} else if (sendOk == 0) {
debug(Sec("(UDP) sendto returned 0"));
debug(("(UDP) sendto returned 0"));
if (c->GetStatus() > -1)
c->SetStatus(-1);
}
#else // unix
if (sendOk == -1) {
debug(Sec("(UDP) Send Failed Code : ") + std::string(strerror(errno)));
debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno)));
if (c->GetStatus() > -1)
c->SetStatus(-1);
} else if (sendOk == 0) {
debug(Sec("(UDP) sendto returned 0"));
debug(("(UDP) sendto returned 0"));
if (c->GetStatus() > -1)
c->SetStatus(-1);
}
#endif // WIN32
}
void AckID(int ID) {
for (PacketData* p : DataAcks) {
if (p != nullptr && p->ID == ID) {
DataAcks.erase(p);
break;
}
}
}
int PacktID() {
static int ID = -1;
if (ID > 999999)
ID = 0;
else
ID++;
return ID;
}
int SplitID() {
static int SID = -1;
if (SID > 999999)
SID = 0;
else
SID++;
return SID;
}
void SendLarge(Client* c, std::string Data) {
Assert(c);
if (Data.length() > 400) {
@@ -105,121 +71,22 @@ void SendLarge(Client* c, std::string Data) {
}
TCPSend(c, Data);
}
struct HandledC {
size_t Pos = 0;
Client* c = nullptr;
std::array<int, 100> HandledIDs = { -1 };
};
std::set<HandledC*> HandledIDs;
void ResetIDs(HandledC* H) {
for (size_t C = 0; C < 100; C++) {
H->HandledIDs.at(C) = -1;
}
}
HandledC* GetHandled(Client* c) {
Assert(c);
for (HandledC* h : HandledIDs) {
if (h->c == c) {
return h;
}
}
return new HandledC();
}
bool Handled(Client* c, int ID) {
Assert(c);
bool handle = false;
for (HandledC* h : HandledIDs) {
if (h->c == c) {
for (int id : h->HandledIDs) {
if (id == ID)
return true;
}
if (h->Pos > 99)
h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
handle = true;
}
}
for (HandledC* h : HandledIDs) {
if (h->c == nullptr || !h->c->isConnected) {
HandledIDs.erase(h);
break;
}
}
if (!handle) {
HandledC* h = GetHandled(c);
ResetIDs(h);
if (h->Pos > 99)
h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
h->c = c;
HandledIDs.insert(h);
}
return false;
}
std::string UDPRcvFromClient(sockaddr_in& client) {
size_t clientLength = sizeof(client);
ZeroMemory(&client, clientLength);
std::string Ret(10240, 0);
int64_t Rcv = recvfrom(UDPSock, &Ret[0], 10240, 0, (sockaddr*)&client, (socklen_t*)&clientLength);
std::array<char, 1024> Ret{};
int64_t Rcv = recvfrom(UDPSock, Ret.data(), Ret.size(), 0, (sockaddr*)&client, (socklen_t*)&clientLength);
if (Rcv == -1) {
#ifdef WIN32
error(Sec("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
#else // unix
error(Sec("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno)));
error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno)));
#endif // WIN32
return "";
}
return Ret.substr(0, Rcv);
return std::string(Ret.begin(), Ret.begin() + Rcv);
}
SplitData* GetSplit(int SplitID) {
for (SplitData* a : SplitPackets) {
if (a->ID == SplitID)
return a;
}
auto* SP = new SplitData();
SplitPackets.insert(SP);
return SP;
}
void HandleChunk(Client* c, const std::string& Data) {
Assert(c);
int pos = FC(Data, "|", 5);
if (pos == -1)
return;
std::stringstream ss(Data.substr(0, size_t(pos++)));
std::string t;
int I = -1;
//Current Max ID SID
std::vector<int> Num(4, 0);
while (std::getline(ss, t, '|')) {
if (I >= 0)
Num.at(size_t(I)) = std::stoi(t);
I++;
}
std::string ack = "TRG:" + std::to_string(Num.at(2));
UDPSend(c, ack);
if (Handled(c, Num.at(2))) {
return;
}
std::string Packet = Data.substr(size_t(pos));
SplitData* SData = GetSplit(Num.at(3));
SData->Total = Num.at(1);
SData->ID = Num.at(3);
SData->Fragments.insert(std::make_pair(Num.at(0), Packet));
if (SData->Fragments.size() == size_t(SData->Total)) {
std::string ToHandle;
for (const std::pair<int, std::string>& a : SData->Fragments) {
ToHandle += a.second;
}
GParser(c, ToHandle);
SplitPackets.erase(SData);
delete SData;
SData = nullptr;
}
}
void UDPParser(Client* c, std::string Packet) {
if (Packet.find("Zp") != std::string::npos && Packet.size() > 500) {
abort();
@@ -228,56 +95,14 @@ void UDPParser(Client* c, std::string Packet) {
if (Packet.substr(0, 4) == "ABG:") {
Packet = DeComp(Packet.substr(4));
}
if (Packet.substr(0, 4) == "TRG:") {
std::string pkt = Packet.substr(4);
if (Packet.find_first_not_of("0123456789") == std::string::npos) {
AckID(stoi(Packet));
}
return;
} else if (Packet.substr(0, 3) == "BD:") {
auto pos = Packet.find(':', 4);
int ID = stoi(Packet.substr(3, pos - 3));
std::string pkt = "TRG:" + std::to_string(ID);
UDPSend(c, pkt);
if (!Handled(c, ID)) {
pkt = Packet.substr(pos + 1);
GParser(c, pkt);
}
return;
} else if (Packet.substr(0, 2) == "SC") {
HandleChunk(c, Packet);
return;
}
GParser(c, Packet);
}
void LOOP() {
DebugPrintTID();
while (UDPSock != -1) {
if (!DataAcks.empty()) {
for (PacketData* p : DataAcks) {
if (p != nullptr) {
if (p->Client == nullptr || p->Client->GetTCPSock() == -1) {
DataAcks.erase(p);
break;
}
if (p->Tries < 15) {
UDPSend(p->Client, p->Data);
p->Tries++;
} else {
DataAcks.erase(p);
break;
}
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}
[[noreturn]] void UDPServerMain() {
#ifdef WIN32
WSADATA data;
if (WSAStartup(514, &data)) {
error(Sec("Can't start Winsock!"));
error(("Can't start Winsock!"));
//return;
}
@@ -290,23 +115,19 @@ void LOOP() {
// Try and bind the socket to the IP and port
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
error(Sec("Can't bind socket!") + std::to_string(WSAGetLastError()));
error(("Can't bind socket!") + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5));
_Exit(-1);
//return;
}
DataAcks.clear();
std::thread Ack(LOOP);
Ack.detach();
info(Sec("Vehicle data network online on port ") + std::to_string(Port) + Sec(" with a Max of ") + std::to_string(MaxPlayers) + Sec(" Clients"));
info(("Vehicle data network online on port ") + std::to_string(Port) + (" with a Max of ") + std::to_string(MaxPlayers) + (" Clients"));
while (true) {
try {
sockaddr_in client {};
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
auto Pos = Data.find(':');
if (Data.empty() || Pos < 0 || Pos > 2)
if (Data.empty() || Pos == std::string::npos || Pos > 2)
continue;
/*char clientIp[256];
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
@@ -320,7 +141,7 @@ void LOOP() {
}
}
} catch (const std::exception& e) {
error(Sec("fatal: ") + std::string(e.what()));
error(("fatal: ") + std::string(e.what()));
}
}
/*CloseSocketProper(UDPSock);
@@ -336,17 +157,13 @@ void LOOP() {
// Try and bind the socket to the IP and port
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) {
error(Sec("Can't bind socket!") + std::string(strerror(errno)));
error(("Can't bind socket!") + std::string(strerror(errno)));
std::this_thread::sleep_for(std::chrono::seconds(5));
_Exit(-1);
//return;
}
DataAcks.clear();
std::thread Ack(LOOP);
Ack.detach();
info(Sec("Vehicle data network online on port ") + std::to_string(Port) + Sec(" with a Max of ") + std::to_string(MaxPlayers) + Sec(" Clients"));
info(("Vehicle data network online on port ") + std::to_string(Port) + (" with a Max of ") + std::to_string(MaxPlayers) + (" Clients"));
while (true) {
try {
sockaddr_in client {};
@@ -366,7 +183,7 @@ void LOOP() {
}
}
} catch (const std::exception& e) {
error(Sec("fatal: ") + std::string(e.what()));
error(("fatal: ") + std::string(e.what()));
}
}
/*CloseSocketProper(UDPSock); // TODO: Why not this? We did this in TCPServerMain?

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 11/6/2020
///
@@ -5,11 +9,11 @@
#include "Logger.h"
#include "Security/Enc.h"
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>*/
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/websocket.hpp>
#include <iostream>
#include <string>
#include <thread>
#include <thread>*/
/*namespace beast = boost::beast;
namespace http = beast::http;
@@ -24,13 +28,13 @@ std::string GetRes(const beast::flat_buffer& buff) {
void SyncData() {
/*DebugPrintTID();
try {
std::string const host = Sec("95.216.35.232");
std::string const host = ("95.216.35.232");
net::io_context ioc;
tcp::resolver r(ioc);
websocket::stream<tcp::socket> ws(ioc);
auto const results = r.resolve(host, Sec("3600"));
auto const results = r.resolve(host, ("3600"));
net::connect(ws.next_layer(), results.begin(), results.end());

View File

@@ -1,3 +1,7 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Server code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 7/17/2020
///
@@ -36,17 +40,7 @@ void SetThreadName(const std::string& Name, bool overwrite) {
}
std::string getDate() {
typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>::type> days;
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::chrono::system_clock::duration tp = now.time_since_epoch();
days d = std::chrono::duration_cast<days>(tp);
tp -= d;
auto h = std::chrono::duration_cast<std::chrono::hours>(tp);
tp -= h;
auto m = std::chrono::duration_cast<std::chrono::minutes>(tp);
tp -= m;
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp);
tp -= s;
time_t tt = std::chrono::system_clock::to_time_t(now);
tm local_tm {};
#ifdef WIN32
@@ -79,9 +73,9 @@ std::string getDate() {
void InitLog() {
std::ofstream LFS;
LFS.open(Sec("Server.log"));
LFS.open(("Server.log"));
if (!LFS.is_open()) {
error(Sec("logger file init failed!"));
error(("logger file init failed!"));
} else
LFS.close();
}
@@ -101,13 +95,13 @@ void DebugPrintTIDInternal(const std::string& func, bool overwrite) {
void addToLog(const std::string& Line) {
std::ofstream LFS;
LFS.open(Sec("Server.log"), std::ios_base::app);
LFS.open(("Server.log"), std::ios_base::app);
LFS << Line.c_str();
LFS.close();
}
void info(const std::string& toPrint) {
std::scoped_lock Guard(LogLock);
std::string Print = getDate() + Sec("[INFO] ") + toPrint + "\n";
std::string Print = getDate() + ("[INFO] ") + toPrint + "\n";
ConsoleOut(Print);
addToLog(Print);
}
@@ -115,25 +109,25 @@ void debug(const std::string& toPrint) {
if (!Debug)
return;
std::scoped_lock Guard(LogLock);
std::string Print = getDate() + Sec("[DEBUG] ") + toPrint + "\n";
std::string Print = getDate() + ("[DEBUG] ") + toPrint + "\n";
ConsoleOut(Print);
addToLog(Print);
}
void warn(const std::string& toPrint) {
std::scoped_lock Guard(LogLock);
std::string Print = getDate() + Sec("[WARN] ") + toPrint + "\n";
std::string Print = getDate() + ("[WARN] ") + toPrint + "\n";
ConsoleOut(Print);
addToLog(Print);
}
void error(const std::string& toPrint) {
std::scoped_lock Guard(LogLock);
std::string Print = getDate() + Sec("[ERROR] ") + toPrint + "\n";
std::string Print = getDate() + ("[ERROR] ") + toPrint + "\n";
ConsoleOut(Print);
addToLog(Print);
}
void except(const std::string& toPrint) {
std::scoped_lock Guard(LogLock);
std::string Print = getDate() + Sec("[EXCEP] ") + toPrint + "\n";
std::string Print = getDate() + ("[EXCEP] ") + toPrint + "\n";
ConsoleOut(Print);
addToLog(Print);
}

View File

@@ -1,18 +1,18 @@
#include "CustomAssert.h"
#include "Security/Xor.h"
#include "Startup.h"
#include <curl/curl.h>
#include <iostream>
#include <thread>
#ifndef WIN32
#include <signal.h>
#include <csignal>
void UnixSignalHandler(int sig) {
switch (sig) {
case SIGPIPE:
warn(Sec("ignored signal SIGPIPE: Pipe broken"));
warn(("ignored signal SIGPIPE: Pipe broken"));
break;
default:
error(Sec("Signal arrived in handler but was not handled: ") + std::to_string(sig));
error(("Signal arrived in handler but was not handled: ") + std::to_string(sig));
break;
}
}
@@ -34,7 +34,8 @@ int main(int argc, char* argv[]) {
#endif // WIN32
DebugPrintTID();
// curl needs to be initialized to properly deallocate its resources later
Assert(curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK);
[[maybe_unused]] auto ret = curl_global_init(CURL_GLOBAL_DEFAULT);
Assert(ret == CURLE_OK);
#ifdef DEBUG
std::thread t1(loop);
t1.detach();