Merge pull request #4 from Starystars67/cross-platform

Cross platform
This commit is contained in:
Lion Kortlepel 2020-11-06 14:30:11 +01:00 committed by GitHub
commit b49abe02eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1336 additions and 732 deletions

5
.clang-format Normal file
View File

@ -0,0 +1,5 @@
---
BasedOnStyle: WebKit
BreakBeforeBraces: Attach
...

1
.gitignore vendored
View File

@ -459,3 +459,4 @@ out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-540e487569703b71
out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T17-35-38-0764.json out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T17-35-38-0764.json
out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-6a61e390ef8eaf17e9f8.json out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-6a61e390ef8eaf17e9f8.json
out/build/x86-Debug/Server.cfg out/build/x86-Debug/Server.cfg
*Server.cfg*

View File

@ -1,9 +1,28 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(Server) project(Server)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s")
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-")
endif ()
find_package(Boost 1.71.0 REQUIRED COMPONENTS system thread)
file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "include/*.h" "include/*/*.h" "include/*.hpp" "include/*/*.hpp") file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "include/*.h" "include/*/*.h" "include/*.hpp" "include/*/*.hpp")
add_executable(${PROJECT_NAME} ${source_files}) add_executable(BeamMP-Server ${source_files})
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Server") target_include_directories(BeamMP-Server PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> ${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} libcurl_a urlmon ws2_32 lua53 zlibstatic)
if (UNIX)
target_link_libraries(BeamMP-Server curl lua5.3 krb5 z pthread stdc++fs ${Boost_LINK_DIRS})
elseif (WIN32)
target_link_libraries(BeamMP-Server libcurl_a urlmon ws2_32 lua53 zlibstatic ${Boost_LINK_DIRS})
endif ()

View File

@ -3,12 +3,13 @@
/// ///
#pragma once #pragma once
#include <mutex> #include <mutex>
#include "CustomAssert.h"
class Client; class Client;
void GParser(Client*c, const std::string&Packet); void GParser(Client*c, const std::string&Packet);
class Buffer{ class Buffer{
public: public:
void Handle(Client*c,const std::string& Data){ void Handle(Client*c,const std::string& Data){
if(c == nullptr)return; Assert(c);
Buf += Data; Buf += Data;
Manage(c); Manage(c);
} }
@ -18,11 +19,12 @@ public:
private: private:
std::string Buf; std::string Buf;
void Manage(Client*c){ void Manage(Client*c){
Assert(c);
if(!Buf.empty()){ if(!Buf.empty()){
std::string::size_type p; std::string::size_type p;
if (Buf.at(0) == '\n'){ if (Buf.at(0) == '\n'){
p = Buf.find('\n',1); p = Buf.find('\n',1);
if(p != -1){ if(p != std::string::npos){
std::string R = Buf.substr(1,p-1); std::string R = Buf.substr(1,p-1);
std::string_view B(R.c_str(),R.find(char(0))); std::string_view B(R.c_str(),R.find(char(0)));
GParser(c, B.data()); GParser(c, B.data());
@ -31,7 +33,7 @@ private:
} }
}else{ }else{
p = Buf.find('\n'); p = Buf.find('\n');
if(p == -1)Buf.clear(); if(p == std::string::npos)Buf.clear();
else{ else{
Buf = Buf.substr(p); Buf = Buf.substr(p);
Manage(c); Manage(c);

View File

@ -3,8 +3,14 @@
/// ///
#pragma once #pragma once
#ifdef WIN32
#include <WS2tcpip.h> #include <WS2tcpip.h>
#else
#include <arpa/inet.h>
#define SOCKET int
#endif
#include "Buffer.h" #include "Buffer.h"
#include "CustomAssert.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <chrono> #include <chrono>
@ -60,6 +66,7 @@ struct ClientInterface{
c = nullptr; c = nullptr;
} }
void AddClient(Client *c){ void AddClient(Client *c){
Assert(c);
Clients.insert(c); Clients.insert(c);
} }
int Size(){ int Size(){

View File

@ -38,7 +38,7 @@
* Define WIN32 when build target is Win32 API * Define WIN32 when build target is Win32 API
*/ */
#if (defined(_WIN32) || defined(__WIN32__)) && \ #if (defined(_WIN32) || defined(WIN32__)) && \
!defined(WIN32) && !defined(__SYMBIAN32__) !defined(WIN32) && !defined(__SYMBIAN32__)
#define WIN32 #define WIN32
#endif #endif

67
include/CustomAssert.h Normal file
View File

@ -0,0 +1,67 @@
// Author: lionkor
/*
* Asserts are to be used anywhere where assumptions about state are made
* implicitly. AssertNotReachable is used where code should never go, like in
* default switch cases which shouldn't trigger. They make it explicit
* that a place cannot normally be reached and make it an error if they do.
*/
#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <thread>
#include "Logger.h"
static const char* const ANSI_RESET = "\u001b[0m";
static const char* const ANSI_BLACK = "\u001b[30m";
static const char* const ANSI_RED = "\u001b[31m";
static const char* const ANSI_GREEN = "\u001b[32m";
static const char* const ANSI_YELLOW = "\u001b[33m";
static const char* const ANSI_BLUE = "\u001b[34m";
static const char* const ANSI_MAGENTA = "\u001b[35m";
static const char* const ANSI_CYAN = "\u001b[36m";
static const char* const ANSI_WHITE = "\u001b[37m";
static const char* const ANSI_BLACK_BOLD = "\u001b[30;1m";
static const char* const ANSI_RED_BOLD = "\u001b[31;1m";
static const char* const ANSI_GREEN_BOLD = "\u001b[32;1m";
static const char* const ANSI_YELLOW_BOLD = "\u001b[33;1m";
static const char* const ANSI_BLUE_BOLD = "\u001b[34;1m";
static const char* const ANSI_MAGENTA_BOLD = "\u001b[35;1m";
static const char* const ANSI_CYAN_BOLD = "\u001b[36;1m";
static const char* const ANSI_WHITE_BOLD = "\u001b[37;1m";
static const char* const ANSI_BOLD = "\u001b[1m";
static const char* const ANSI_UNDERLINE = "\u001b[4m";
#if DEBUG
inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const char* function, [[maybe_unused]] unsigned line,
[[maybe_unused]] const char* condition_string, [[maybe_unused]] bool result) {
if (!result) {
std::cout << std::flush << "(debug build) TID "
<< std::this_thread::get_id() << ": ASSERTION FAILED: at "
<< file << ":" << line << " \n\t-> in "
<< function << ", Line " << line << ": \n\t\t-> "
<< "Failed Condition: " << condition_string << std::endl;
std::cout << "... terminating ..." << std::endl;
abort();
}
}
#define Assert(cond) _assert(__FILE__, __func__, __LINE__, #cond, (cond))
#define AssertNotReachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false)
#else
// In release build, these macros turn into NOPs. The compiler will optimize these out.
#define Assert(x) \
do { \
} while (false)
#define AssertNotReachable() \
do { \
} while (false)
#endif // DEBUG

View File

@ -2,10 +2,15 @@
/// Created by Anonymous275 on 4/2/2020. /// Created by Anonymous275 on 4/2/2020.
/// ///
#pragma once #pragma once
#include <string>
#include <iostream> #include <iostream>
#include <mutex>
#include <string>
extern std::mutex MLock;
void InitLog(); void InitLog();
#define DebugPrintTID() DebugPrintTIDInternal(__func__)
void DebugPrintTIDInternal(const std::string& func); // prints the current thread id in debug mode, to make tracing of crashes and asserts easier
void ConsoleOut(const std::string& msg); void ConsoleOut(const std::string& msg);
void QueueAbort();
void except(const std::string& toPrint); void except(const std::string& toPrint);
void debug(const std::string& toPrint); void debug(const std::string& toPrint);
void error(const std::string& toPrint); void error(const std::string& toPrint);

View File

@ -3,32 +3,36 @@
/// ///
#pragma once #pragma once
#include "lua.hpp"
#include <any>
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#include "lua.hpp" #include <memory>
#include <vector>
#include <thread>
#include <mutex> #include <mutex>
#include <set> #include <set>
#include <any> #include <thread>
namespace fs = std::experimental::filesystem; #include <vector>
struct LuaArg{
namespace fs = std::filesystem;
struct LuaArg {
std::vector<std::any> args; std::vector<std::any> args;
void PushArgs(lua_State *State){ void PushArgs(lua_State* State) {
for(std::any arg : args){ for (std::any arg : args) {
if(!arg.has_value())return; if (!arg.has_value())
return;
std::string Type = arg.type().name(); std::string Type = arg.type().name();
if(Type.find("bool") != -1){ if (Type.find("bool") != std::string::npos) {
lua_pushboolean(State,std::any_cast<bool>(arg)); lua_pushboolean(State, std::any_cast<bool>(arg));
} }
if(Type.find("basic_string") != -1 || Type.find("char") != -1){ if (Type.find("basic_string") != std::string::npos || Type.find("char") != std::string::npos) {
lua_pushstring(State,std::any_cast<std::string>(arg).c_str()); lua_pushstring(State, std::any_cast<std::string>(arg).c_str());
} }
if(Type.find("int") != -1){ if (Type.find("int") != std::string::npos) {
lua_pushinteger(State,std::any_cast<int>(arg)); lua_pushinteger(State, std::any_cast<int>(arg));
} }
if(Type.find("float") != -1){ if (Type.find("float") != std::string::npos) {
lua_pushnumber(State,std::any_cast<float>(arg)); lua_pushnumber(State, std::any_cast<float>(arg));
} }
} }
} }
@ -36,32 +40,39 @@ struct LuaArg{
class Lua { class Lua {
private: private:
std::set<std::pair<std::string,std::string>> RegisteredEvents; std::set<std::pair<std::string, std::string>> _RegisteredEvents;
lua_State *luaState = luaL_newstate(); lua_State* luaState { nullptr };
fs::file_time_type LastWrote; fs::file_time_type _LastWrote;
std::string PluginName; std::string _PluginName;
std::string FileName; std::string _FileName;
bool _StopThread = false;
bool _Console = false;
// this is called by the ctor to ensure RAII
void Init();
public: public:
void RegisterEvent(const std::string&Event,const std::string&FunctionName); void RegisterEvent(const std::string& Event, const std::string& FunctionName);
std::string GetRegistered(const std::string&Event); std::string GetRegistered(const std::string& Event) const;
void UnRegisterEvent(const std::string&Event); void UnRegisterEvent(const std::string& Event);
void SetLastWrite(fs::file_time_type time); void SetLastWrite(fs::file_time_type time);
bool IsRegistered(const std::string&Event); bool IsRegistered(const std::string& Event);
void SetPluginName(const std::string&Name); void SetPluginName(const std::string& Name);
void Execute(const std::string& Command); void Execute(const std::string& Command);
void SetFileName(const std::string&Name); void SetFileName(const std::string& Name);
fs::file_time_type GetLastWrite(); fs::file_time_type GetLastWrite();
std::string GetPluginName(); std::string GetPluginName() const;
std::string GetFileName(); std::string GetFileName() const;
bool StopThread = false;
bool Console = false;
lua_State* GetState(); lua_State* GetState();
char* GetOrigin(); const lua_State* GetState() const;
std::string GetOrigin();
std::mutex Lock; std::mutex Lock;
void Reload(); void Reload();
void Init(); Lua(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote, bool Console = false);
Lua(bool Console = false);
~Lua();
void SetStopThread(bool StopThread) { _StopThread = StopThread; }
bool GetStopThread() const { return _StopThread; }
}; };
int CallFunction(Lua*lua,const std::string& FuncName,LuaArg* args); int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> args);
int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller,LuaArg* arg,bool Wait); int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait);
extern std::set<Lua*> PluginEngine; extern std::set<std::unique_ptr<Lua>> PluginEngine;

View File

@ -706,7 +706,7 @@
** Define it as a help when debugging C code. ** Define it as a help when debugging C code.
*/ */
#if defined(LUA_USE_APICHECK) #if defined(LUA_USE_APICHECK)
#include <assert.h> #include <CustomAssert.h>
#define luai_apicheck(l,e) assert(e) #define luai_apicheck(l,e) assert(e)
#endif #endif

View File

@ -2,7 +2,11 @@
/// Created by Anonymous275 on 7/28/2020 /// Created by Anonymous275 on 7/28/2020
/// ///
#pragma once #pragma once
#ifdef __linux
#define EXCEPTION_POINTERS void
#else
#include <WS2tcpip.h> #include <WS2tcpip.h>
#endif
#include <string> #include <string>
#include "Xor.h" #include "Xor.h"
struct RSA{ struct RSA{

View File

@ -5,6 +5,7 @@
#include <string> #include <string>
#include <array> #include <array>
#include <cstdarg> #include <cstdarg>
#include <cstdio>
#define BEGIN_NAMESPACE(x) namespace x { #define BEGIN_NAMESPACE(x) namespace x {
#define END_NAMESPACE } #define END_NAMESPACE }
@ -68,10 +69,10 @@ BEGIN_NAMESPACE(XorCompileTime)
public: public:
template <size_t... Is> template <size_t... Is>
constexpr __forceinline XorString(const Char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... } constexpr inline XorString(const Char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... }
{} {}
__forceinline decltype(auto) decrypt(){ inline decltype(auto) decrypt(){
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]); _encrypted[i] = dec(_encrypted[i]);
} }
@ -83,14 +84,14 @@ BEGIN_NAMESPACE(XorCompileTime)
static auto w_printf = [](const char* fmt, ...) { static auto w_printf = [](const char* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vprintf_s(fmt, args); vprintf(fmt, args);
va_end(args); va_end(args);
}; };
static auto w_printf_s = [](const char* fmt, ...) { static auto w_printf_s = [](const char* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vprintf_s(fmt, args); vprintf(fmt, args);
va_end(args); va_end(args);
}; };
@ -113,7 +114,7 @@ BEGIN_NAMESPACE(XorCompileTime)
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) { static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vsprintf_s(buf, buf_size, fmt, args); vsnprintf(buf, buf_size, fmt, args);
va_end(args); va_end(args);
}; };
@ -121,7 +122,7 @@ BEGIN_NAMESPACE(XorCompileTime)
int ret; int ret;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ret = vsprintf_s(buf, buf_size, fmt, args); ret = vsnprintf(buf, buf_size, fmt, args);
va_end(args); va_end(args);
return ret; return ret;
}; };

30
include/UnixCompat.h Normal file
View File

@ -0,0 +1,30 @@
// Author: lionkor
#pragma once
// This header defines unix equivalents of common win32 functions.
#ifndef WIN32
#include "CustomAssert.h"
#include <cstring>
#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);
}
// provides unix equivalent of closesocket call in win32
inline void closesocket(int socket) {
close(socket);
}
#ifndef __try
#define __try
#endif
#ifndef __except
#define __except(x) /**/
#endif
#endif // WIN32

View File

@ -176,7 +176,7 @@
#if defined(_WINDOWS) && !defined(WINDOWS) #if defined(_WINDOWS) && !defined(WINDOWS)
# define WINDOWS # define WINDOWS
#endif #endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) #if defined(_WIN32) || defined(_WIN32_WCE) || defined(WIN32__)
# ifndef WIN32 # ifndef WIN32
# define WIN32 # define WIN32
# endif # endif

View File

@ -133,7 +133,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#if defined(MACOS) || defined(TARGET_OS_MAC) #if defined(MACOS) || defined(TARGET_OS_MAC)
# define OS_CODE 7 # define OS_CODE 7
# ifndef Z_SOLO # ifndef Z_SOLO
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != WIN32_os
# include <unix.h> /* for fdopen */ # include <unix.h> /* for fdopen */
# else # else
# ifndef fdopen # ifndef fdopen

View File

@ -3,11 +3,15 @@
/// ///
#include "Zlib/zlib.h" #include "Zlib/zlib.h"
#include <iostream> #include <iostream>
#include <cstring>
#include <algorithm>
#include <array>
#define Biggest 30000 #define Biggest 30000
std::string Comp(std::string Data){ std::string Comp(std::string Data){
char*C = new char[Biggest]; std::array<char, Biggest> C;
memset(C, 0, Biggest); // obsolete
C.fill(0);
z_stream defstream; z_stream defstream;
defstream.zalloc = Z_NULL; defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL; defstream.zfree = Z_NULL;
@ -15,20 +19,20 @@ std::string Comp(std::string Data){
defstream.avail_in = (uInt)Data.length(); defstream.avail_in = (uInt)Data.length();
defstream.next_in = (Bytef *)&Data[0]; defstream.next_in = (Bytef *)&Data[0];
defstream.avail_out = Biggest; defstream.avail_out = Biggest;
defstream.next_out = reinterpret_cast<Bytef *>(C); defstream.next_out = reinterpret_cast<Bytef *>(C.data());
deflateInit(&defstream, Z_BEST_COMPRESSION); deflateInit(&defstream, Z_BEST_COMPRESSION);
deflate(&defstream, Z_SYNC_FLUSH); deflate(&defstream, Z_SYNC_FLUSH);
deflate(&defstream, Z_FINISH); deflate(&defstream, Z_FINISH);
deflateEnd(&defstream); deflateEnd(&defstream);
int TO = defstream.total_out; size_t TO = defstream.total_out;
std::string Ret(TO,0); std::string Ret(TO,0);
memcpy_s(&Ret[0],TO,C,TO); std::copy_n(C.begin(), TO, Ret.begin());
delete [] C;
return Ret; return Ret;
} }
std::string DeComp(std::string Compressed){ std::string DeComp(std::string Compressed){
char*C = new char[Biggest]; std::array<char, Biggest> C;
memset(C, 0, Biggest); // not needed
C.fill(0);
z_stream infstream; z_stream infstream;
infstream.zalloc = Z_NULL; infstream.zalloc = Z_NULL;
infstream.zfree = Z_NULL; infstream.zfree = Z_NULL;
@ -36,14 +40,13 @@ std::string DeComp(std::string Compressed){
infstream.avail_in = Biggest; infstream.avail_in = Biggest;
infstream.next_in = (Bytef *)(&Compressed[0]); infstream.next_in = (Bytef *)(&Compressed[0]);
infstream.avail_out = Biggest; infstream.avail_out = Biggest;
infstream.next_out = (Bytef *)(C); infstream.next_out = (Bytef *)(C.data());
inflateInit(&infstream); inflateInit(&infstream);
inflate(&infstream, Z_SYNC_FLUSH); inflate(&infstream, Z_SYNC_FLUSH);
inflate(&infstream, Z_FINISH); inflate(&infstream, Z_FINISH);
inflateEnd(&infstream); inflateEnd(&infstream);
int TO = infstream.total_out; size_t TO = infstream.total_out;
std::string Ret(TO,0); std::string Ret(TO,0);
memcpy_s(&Ret[0],TO,C,TO); std::copy_n(C.begin(), TO, Ret.begin());
delete [] C;
return Ret; return Ret;
} }

View File

@ -3,58 +3,95 @@
/// ///
#include "Lua/LuaSystem.hpp" #include "Lua/LuaSystem.hpp"
#ifdef WIN32
#include <conio.h>
#include <windows.h> #include <windows.h>
#else // *nix
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
#include <termios.h>
#include <unistd.h>
#endif // WIN32
#include "Logger.h" #include "Logger.h"
#include <iostream> #include <iostream>
#include <conio.h> #include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex>
std::vector<std::string> QConsoleOut; std::vector<std::string> QConsoleOut;
std::string CInputBuff; std::string CInputBuff;
std::mutex MLock; std::mutex MLock;
Lua* LuaConsole; std::unique_ptr<Lua> LuaConsole;
void HandleInput(const std::string& cmd){ void HandleInput(const std::string& cmd) {
std::cout << std::endl;
if (cmd == "exit") { if (cmd == "exit") {
exit(0); exit(0);
}else LuaConsole->Execute(cmd); } else
LuaConsole->Execute(cmd);
} }
void ProcessOut(){ void ProcessOut() {
static size_t len = 2; static size_t len = 2;
if(QConsoleOut.empty() && len == CInputBuff.length())return; if (QConsoleOut.empty() && len == CInputBuff.length())
return;
printf("%c[2K\r", 27); printf("%c[2K\r", 27);
for(const std::string& msg : QConsoleOut) for (const std::string& msg : QConsoleOut)
if(!msg.empty())std::cout << msg; if (!msg.empty())
std::cout << msg;
MLock.lock(); MLock.lock();
QConsoleOut.clear(); QConsoleOut.clear();
MLock.unlock(); MLock.unlock();
std::cout << "> " << CInputBuff; std::cout << "> " << CInputBuff << std::flush;
len = CInputBuff.length(); len = CInputBuff.length();
} }
void ConsoleOut(const std::string& msg){ void ConsoleOut(const std::string& msg) {
MLock.lock(); MLock.lock();
QConsoleOut.emplace_back(msg); QConsoleOut.emplace_back(msg);
MLock.unlock(); MLock.unlock();
} }
[[noreturn]] void OutputRefresh(){ [[noreturn]] void OutputRefresh() {
while(true){ DebugPrintTID();
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
ProcessOut(); ProcessOut();
} }
} }
void SetupConsole(){
#ifndef WIN32
static int _getch() {
char buf = 0;
struct termios old;
fflush(stdout);
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~unsigned(ICANON);
old.c_lflag &= ~unsigned(ECHO);
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
if (read(0, &buf, 1) < 0)
perror("read()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, &old) < 0)
perror("tcsetattr ~ICANON");
// no echo printf("%c\n", buf);
return buf;
}
#endif // WIN32
void SetupConsole() {
#ifdef WIN32
DWORD outMode = 0; DWORD outMode = 0;
HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (stdoutHandle == INVALID_HANDLE_VALUE){ if (stdoutHandle == INVALID_HANDLE_VALUE) {
error("Invalid handle"); error("Invalid handle");
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
exit(GetLastError()); exit(GetLastError());
} }
if (!GetConsoleMode(stdoutHandle, &outMode)){ if (!GetConsoleMode(stdoutHandle, &outMode)) {
error("Invalid console mode"); error("Invalid console mode");
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
exit(GetLastError()); exit(GetLastError());
@ -66,25 +103,34 @@ void SetupConsole(){
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
exit(GetLastError()); exit(GetLastError());
} }
#else
#endif // WIN32
} }
[[noreturn]] void ReadCin(){
while (true){ [[noreturn]] void ReadCin() {
DebugPrintTID();
while (true) {
int In = _getch(); int In = _getch();
if (In == 13) { if (In == 13 || In == '\n') {
if(!CInputBuff.empty()) { if (!CInputBuff.empty()) {
HandleInput(CInputBuff); HandleInput(CInputBuff);
CInputBuff.clear(); CInputBuff.clear();
} }
}else if(In == 8){ } else if (In == 8) {
if(!CInputBuff.empty())CInputBuff.pop_back(); if (!CInputBuff.empty())
}else CInputBuff += char(In); CInputBuff.pop_back();
} else if (In == 4) {
CInputBuff = "exit";
HandleInput(CInputBuff);
CInputBuff.clear();
} else {
CInputBuff += char(In);
}
} }
} }
void ConsoleInit(){ void ConsoleInit() {
SetupConsole(); SetupConsole();
LuaConsole = new Lua(); LuaConsole = std::make_unique<Lua>(true);
LuaConsole->Console = true;
LuaConsole->Init();
printf("> "); printf("> ");
std::thread In(ReadCin); std::thread In(ReadCin);
In.detach(); In.detach();

View File

@ -3,7 +3,8 @@
/// ///
#include "Security/Enc.h" #include "Security/Enc.h"
#include "Settings.h" #include "Settings.h"
#include <windows.h> #include "CustomAssert.h"
//#include <windows.h>
#include "Logger.h" #include "Logger.h"
#include <sstream> #include <sstream>
#include <thread> #include <thread>
@ -84,7 +85,9 @@ int Dec(int value,int d,int n){
return log_power(value, d, n); return log_power(value, d, n);
} }
#ifdef WIN32
int Handle(EXCEPTION_POINTERS *ep,char* Origin){ int Handle(EXCEPTION_POINTERS *ep,char* Origin){
Assert(false);
std::stringstream R; std::stringstream R;
R << Sec("Code : ") << std::hex R << Sec("Code : ") << std::hex
<< ep->ExceptionRecord->ExceptionCode << ep->ExceptionRecord->ExceptionCode
@ -92,6 +95,10 @@ int Handle(EXCEPTION_POINTERS *ep,char* Origin){
except(R.str()); except(R.str());
return 1; return 1;
} }
#else
// stub
int Handle(EXCEPTION_POINTERS *, char*) { return 1; }
#endif // WIN32
std::string RSA_E(const std::string& Data, RSA*k){ std::string RSA_E(const std::string& Data, RSA*k){
std::stringstream stream; std::stringstream stream;

View File

@ -3,6 +3,7 @@
/// ///
#include "Security/Enc.h" #include "Security/Enc.h"
#include "Logger.h" #include "Logger.h"
#include "CustomAssert.h"
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <thread> #include <thread>
@ -33,13 +34,13 @@ void SetValues(const std::string& Line, int Index) {
} }
Data = Data.substr(1); Data = Data.substr(1);
std::string::size_type sz; std::string::size_type sz;
bool Boolean = std::string(Data).find("true") != -1;//searches for "true" bool FoundTrue = std::string(Data).find("true") != std::string::npos;//searches for "true"
switch (Index) { switch (Index) {
case 1 : case 1 :
Debug = Boolean;//checks and sets the Debug Value Debug = FoundTrue;//checks and sets the Debug Value
break; break;
case 2 : case 2 :
Private = Boolean;//checks and sets the Private Value Private = FoundTrue;//checks and sets the Private Value
break; break;
case 3 : case 3 :
Port = std::stoi(Data, &sz);//sets the Port Port = std::stoi(Data, &sz);//sets the Port
@ -77,6 +78,7 @@ std::string RemoveComments(const std::string& Line){
return Return; return Return;
} }
void LoadConfig(std::ifstream& IFS){ void LoadConfig(std::ifstream& IFS){
Assert(IFS.is_open());
std::string line; std::string line;
int index = 1; int index = 1;
while (getline(IFS, line)) { while (getline(IFS, line)) {

View File

@ -29,6 +29,7 @@ std::string GenerateCall(){
return ret; return ret;
} }
void Heartbeat(){ void Heartbeat(){
DebugPrintTID();
std::string R,T; std::string R,T;
while(true){ while(true){
R = GenerateCall(); R = GenerateCall();

View File

@ -6,7 +6,9 @@
#include "Settings.h" #include "Settings.h"
#include <algorithm> #include <algorithm>
#include "Logger.h" #include "Logger.h"
namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem;
uint64_t MaxModSize = 0; uint64_t MaxModSize = 0;
std::string FileSizes; std::string FileSizes;
std::string FileList; std::string FileList;

View File

@ -5,6 +5,7 @@
#include "Client.hpp" #include "Client.hpp"
#include "Logger.h" #include "Logger.h"
#include <string> #include <string>
#include <algorithm>
std::string CustomIP; std::string CustomIP;
std::string GetSVer(){ std::string GetSVer(){

View File

@ -2,80 +2,84 @@
/// Created by Anonymous275 on 5/20/2020 /// Created by Anonymous275 on 5/20/2020
/// ///
#include "Logger.h"
#include "Lua/LuaSystem.hpp" #include "Lua/LuaSystem.hpp"
#include "Security/Enc.h" #include "Security/Enc.h"
#include "Settings.h" #include "Settings.h"
#include "Logger.h"
#include <thread> #include <thread>
std::set<Lua*> PluginEngine; #ifdef __linux
bool NewFile(const std::string&Path){ // we need this for `struct stat`
for(Lua*Script : PluginEngine){ #include <sys/stat.h>
if(Path == Script->GetFileName())return false; #endif // __linux
std::set<std::unique_ptr<Lua>> PluginEngine;
bool NewFile(const std::string& Path) {
for (auto& Script : PluginEngine) {
if (Path == Script->GetFileName())
return false;
} }
return true; return true;
} }
void RegisterFiles(const std::string& Path,bool HotSwap){ void RegisterFiles(const std::string& Path, bool HotSwap) {
std::string Name = Path.substr(Path.find_last_of('\\')+1); std::string Name = Path.substr(Path.find_last_of('\\') + 1);
if(!HotSwap)info(Sec("Loading plugin : ") + Name); if (!HotSwap)
for (const auto &entry : fs::directory_iterator(Path)){ info(Sec("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(Sec(".lua"));
if (pos != std::string::npos && entry.path().string().length() - pos == 4) { if (pos != std::string::npos && entry.path().string().length() - pos == 4) {
if(!HotSwap || NewFile(entry.path().string())){ if (!HotSwap || NewFile(entry.path().string())) {
Lua *Script = new Lua(); auto FileName = entry.path().string();
PluginEngine.insert(Script); std::unique_ptr<Lua> ScriptToInsert(new Lua(Name, FileName, fs::last_write_time(FileName)));
Script->SetFileName(entry.path().string()); auto& Script = *ScriptToInsert;
Script->SetPluginName(Name); PluginEngine.insert(std::move(ScriptToInsert));
Script->SetLastWrite(fs::last_write_time(Script->GetFileName())); if (HotSwap)
Script->Init(); info(Sec("[HOTSWAP] Added : ") + Script.GetFileName().substr(Script.GetFileName().find('\\')));
if(HotSwap)info(Sec("[HOTSWAP] Added : ") +
Script->GetFileName().substr(Script->GetFileName().find('\\')));
} }
} }
} }
} }
void FolderList(const std::string& Path,bool HotSwap){ void FolderList(const std::string& Path, bool HotSwap) {
for (const auto &entry : fs::directory_iterator(Path)) { for (const auto& entry : fs::directory_iterator(Path)) {
auto pos = entry.path().filename().string().find('.'); auto pos = entry.path().filename().string().find('.');
if (pos == std::string::npos) { if (pos == std::string::npos) {
RegisterFiles(entry.path().string(),HotSwap); RegisterFiles(entry.path().string(), HotSwap);
} }
} }
} }
[[noreturn]]void HotSwaps(const std::string& path){ [[noreturn]] void HotSwaps(const std::string& path) {
while(true){ DebugPrintTID();
for(Lua*Script : PluginEngine){ while (true) {
struct stat Info{}; for (auto& Script : PluginEngine) {
if(stat(Script->GetFileName().c_str(), &Info) != 0){ struct stat Info {};
Script->StopThread = true; if (stat(Script->GetFileName().c_str(), &Info) != 0) {
Script->SetStopThread(true);
PluginEngine.erase(Script); PluginEngine.erase(Script);
info(Sec("[HOTSWAP] Removed : ")+ info(Sec("[HOTSWAP] Removed : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
Script->GetFileName().substr(Script->GetFileName().find('\\')));
break; break;
} }
if(Script->GetLastWrite() != fs::last_write_time(Script->GetFileName())){ if (Script->GetLastWrite() != fs::last_write_time(Script->GetFileName())) {
Script->StopThread = true; Script->SetStopThread(true);
info(Sec("[HOTSWAP] Updated : ")+ info(Sec("[HOTSWAP] Updated : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
Script->GetFileName().substr(Script->GetFileName().find('\\')));
Script->SetLastWrite(fs::last_write_time(Script->GetFileName())); Script->SetLastWrite(fs::last_write_time(Script->GetFileName()));
Script->Reload(); Script->Reload();
} }
} }
FolderList(path,true); FolderList(path, true);
std::this_thread::sleep_for(std::chrono::seconds(2)); std::this_thread::sleep_for(std::chrono::seconds(2));
} }
} }
void InitLua(){ void InitLua() {
if(!fs::exists(Resource)){ if (!fs::exists(Resource)) {
fs::create_directory(Resource); fs::create_directory(Resource);
} }
std::string Path = Resource + Sec("/Server"); std::string Path = Resource + Sec("/Server");
if(!fs::exists(Path)){ if (!fs::exists(Path)) {
fs::create_directory(Path); fs::create_directory(Path);
} }
FolderList(Path,false); FolderList(Path, false);
std::thread t1(HotSwaps,Path); std::thread t1(HotSwaps, Path);
t1.detach(); t1.detach();
info(Sec("Lua system online")); info(Sec("Lua system online"));
} }

View File

@ -3,439 +3,509 @@
/// ///
#include "Lua/LuaSystem.hpp" #include "Lua/LuaSystem.hpp"
#include "Security/Enc.h"
#include "Client.hpp" #include "Client.hpp"
#include "Settings.h"
#include "Network.h"
#include "Logger.h" #include "Logger.h"
#include <iostream> #include "Network.h"
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <future> #include <future>
#include <iostream>
#include <utility> #include <utility>
#include <optional>
LuaArg* CreateArg(lua_State *L,int T,int S){ std::unique_ptr<LuaArg> CreateArg(lua_State* L, int T, int S) {
if(S > T)return nullptr; if (S > T)
auto* temp = new LuaArg; return nullptr;
for(int C = S;C <= T;C++){ std::unique_ptr<LuaArg> temp(new LuaArg);
if(lua_isstring(L,C)){ for (int C = S; C <= T; C++) {
temp->args.emplace_back(std::string(lua_tostring(L,C))); if (lua_isstring(L, C)) {
}else if(lua_isinteger(L,C)){ temp->args.emplace_back(std::string(lua_tostring(L, C)));
temp->args.emplace_back(int(lua_tointeger(L,C))); } else if (lua_isinteger(L, C)) {
}else if(lua_isboolean(L,C)){ temp->args.emplace_back(int(lua_tointeger(L, C)));
temp->args.emplace_back(bool(lua_toboolean(L,C))); } else if (lua_isboolean(L, C)) {
}else if(lua_isnumber(L,C)) { temp->args.emplace_back(bool(lua_toboolean(L, C)));
} else if (lua_isnumber(L, C)) {
temp->args.emplace_back(float(lua_tonumber(L, C))); temp->args.emplace_back(float(lua_tonumber(L, C)));
} }
} }
return temp; return temp;
} }
void ClearStack(lua_State *L){ void ClearStack(lua_State* L) {
lua_settop(L,0); lua_settop(L, 0);
} }
Lua* GetScript(lua_State *L){ std::optional<std::reference_wrapper<Lua>> GetScript(lua_State* L) {
for(Lua*Script : PluginEngine){ for (auto& Script : PluginEngine) {
if (Script->GetState() == L)return Script; if (Script->GetState() == L)
return *Script;
} }
return nullptr; return std::nullopt;
} }
void SendError(lua_State *L,const std::string&msg){ void SendError(lua_State* L, const std::string& msg) {
Lua* S = GetScript(L); Assert(L);
auto MaybeS = GetScript(L);
std::string a; std::string a;
if(S == nullptr)a = Sec("Console"); if (!MaybeS.has_value()) {
else a = S->GetFileName().substr(S->GetFileName().find('\\')); a = Sec("_Console");
} else {
Lua& S = MaybeS.value();
a = S.GetFileName().substr(S.GetFileName().find('\\'));
}
warn(a + Sec(" | Incorrect Call of ") + msg); warn(a + Sec(" | Incorrect Call of ") + msg);
} }
int Trigger(Lua*lua,const std::string& R, LuaArg*arg){ int Trigger(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg) {
std::lock_guard<std::mutex> lockGuard(lua->Lock); std::lock_guard<std::mutex> lockGuard(lua->Lock);
std::packaged_task<int()> task([lua,R,arg]{return CallFunction(lua,R,arg);}); 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::future<int> f1 = task.get_future();
std::thread t(std::move(task)); std::thread t(std::move(task), std::move(arg));
t.detach(); t.detach();
auto status = f1.wait_for(std::chrono::seconds(5)); auto status = f1.wait_for(std::chrono::seconds(5));
if(status != std::future_status::timeout)return f1.get(); if (status != std::future_status::timeout)
SendError(lua->GetState(),R + " took too long to respond"); return f1.get();
SendError(lua->GetState(), R + " took too long to respond");
return 0; return 0;
} }
int FutureWait(Lua*lua,const std::string& R, LuaArg*arg,bool Wait){ int FutureWait(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg, bool Wait) {
std::packaged_task<int()> task([lua,R,arg]{return Trigger(lua,R,arg);}); 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::future<int> f1 = task.get_future();
std::thread t(std::move(task)); std::thread t(std::move(task), std::move(arg));
t.detach(); t.detach();
int T = 0; int T = 0;
if(Wait)T = 6; if (Wait)
T = 6;
auto status = f1.wait_for(std::chrono::seconds(T)); auto status = f1.wait_for(std::chrono::seconds(T));
if(status != std::future_status::timeout)return f1.get(); if (status != std::future_status::timeout)
return f1.get();
return 0; return 0;
} }
int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller,LuaArg* arg,bool Wait){ int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait) {
int R = 0; int R = 0;
for(Lua*Script : PluginEngine){ for (auto& Script : PluginEngine) {
if(Script->IsRegistered(Event)){ if (Script->IsRegistered(Event)) {
if(local){ if (local) {
if (Script->GetPluginName() == Caller->GetPluginName()){ if (Script->GetPluginName() == Caller->GetPluginName()) {
R += FutureWait(Script,Script->GetRegistered(Event),arg,Wait); R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
} }
}else R += FutureWait(Script,Script->GetRegistered(Event), arg,Wait); } else
R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
} }
} }
return R; return R;
} }
bool ConsoleCheck(lua_State *L, int r){ bool ConsoleCheck(lua_State* L, int r) {
if (r != LUA_OK){ if (r != LUA_OK) {
std::string msg = lua_tostring(L, -1); std::string msg = lua_tostring(L, -1);
warn(Sec("Console | ") + msg); warn(Sec("_Console | ") + msg);
return false; return false;
} }
return true; return true;
} }
bool CheckLua(lua_State *L, int r){ bool CheckLua(lua_State* L, int r) {
if (r != LUA_OK){ if (r != LUA_OK) {
std::string msg = lua_tostring(L, -1); std::string msg = lua_tostring(L, -1);
Lua * S = GetScript(L); auto MaybeS = GetScript(L);
std::string a = S->GetFileName().substr(S->GetFileName().find('\\')); if (MaybeS.has_value()) {
Lua& S = MaybeS.value();
std::string a = S.GetFileName().substr(S.GetFileName().find('\\'));
warn(a + " | " + msg); warn(a + " | " + msg);
return false; return false;
} }
// What the fuck, what do we do?!
AssertNotReachable();
}
return true; return true;
} }
int lua_RegisterEvent(lua_State *L){ int lua_RegisterEvent(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
Lua* Script = GetScript(L); auto MaybeScript = GetScript(L);
if(Args == 2 && lua_isstring(L,1) && lua_isstring(L,2)){ Assert(MaybeScript.has_value());
Script->RegisterEvent(lua_tostring(L,1),lua_tostring(L,2)); Lua& Script = MaybeScript.value();
}else SendError(L,Sec("RegisterEvent invalid argument count expected 2 got ") + std::to_string(Args)); 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));
return 0; return 0;
} }
int lua_TriggerEventL(lua_State *L){ int lua_TriggerEventL(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
Lua* Script = GetScript(L); auto MaybeScript = GetScript(L);
if(Args > 0){ Assert(MaybeScript.has_value());
if(lua_isstring(L,1)){ Lua& Script = MaybeScript.value();
TriggerLuaEvent(lua_tostring(L, 1), true, Script, CreateArg(L,Args,2),false); if (Args > 0) {
}else SendError(L,Sec("TriggerLocalEvent wrong argument [1] need string")); if (lua_isstring(L, 1)) {
}else{ TriggerLuaEvent(lua_tostring(L, 1), true, &Script, CreateArg(L, Args, 2), false);
SendError(L,Sec("TriggerLocalEvent not enough arguments expected 1 got 0")); } else
SendError(L, Sec("TriggerLocalEvent wrong argument [1] need string"));
} else {
SendError(L, Sec("TriggerLocalEvent not enough arguments expected 1 got 0"));
} }
return 0; return 0;
} }
int lua_TriggerEventG(lua_State *L){ int lua_TriggerEventG(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
Lua* Script = GetScript(L); auto MaybeScript = GetScript(L);
if(Args > 0){ Assert(MaybeScript.has_value());
if(lua_isstring(L,1)) { Lua& Script = MaybeScript.value();
TriggerLuaEvent(lua_tostring(L, 1), false, Script, CreateArg(L,Args,2),false); if (Args > 0) {
}else SendError(L,Sec("TriggerGlobalEvent wrong argument [1] need string")); if (lua_isstring(L, 1)) {
}else SendError(L,Sec("TriggerGlobalEvent not enough arguments")); TriggerLuaEvent(lua_tostring(L, 1), false, &Script, CreateArg(L, Args, 2), false);
} else
SendError(L, Sec("TriggerGlobalEvent wrong argument [1] need string"));
} else
SendError(L, Sec("TriggerGlobalEvent not enough arguments"));
return 0; return 0;
} }
char* ThreadOrigin(Lua*lua){ char* ThreadOrigin(Lua* lua) {
std::string T = "Thread in " + lua->GetFileName().substr(lua->GetFileName().find('\\')); std::string T = "Thread in " + lua->GetFileName().substr(lua->GetFileName().find('\\'));
char* Data = new char[T.size()+1]; char* Data = new char[T.size() + 1];
ZeroMemory(Data,T.size()+1); ZeroMemory(Data, T.size() + 1);
memcpy_s(Data,T.size(),T.c_str(),T.size()); memcpy(Data, T.c_str(), T.size());
return Data; return Data;
} }
void SafeExecution(Lua* lua,const std::string& FuncName){ void SafeExecution(Lua* lua, const std::string& FuncName) {
lua_State* luaState = lua->GetState(); lua_State* luaState = lua->GetState();
lua_getglobal(luaState, FuncName.c_str()); lua_getglobal(luaState, FuncName.c_str());
if(lua_isfunction(luaState, -1)) { if (lua_isfunction(luaState, -1)) {
char* Origin = ThreadOrigin(lua); char* Origin = ThreadOrigin(lua);
__try{ #ifdef WIN32
__try {
int R = lua_pcall(luaState, 0, 0, 0); int R = lua_pcall(luaState, 0, 0, 0);
CheckLua(luaState, R); CheckLua(luaState, R);
}__except(Handle(GetExceptionInformation(),Origin)){} } __except (Handle(GetExceptionInformation(), Origin)) {
delete [] Origin; }
#else // unix
int R = lua_pcall(luaState, 0, 0, 0);
CheckLua(luaState, R);
#endif // WIN32
delete[] Origin;
} }
ClearStack(luaState); ClearStack(luaState);
} }
void ExecuteAsync(Lua* lua,const std::string& FuncName){ void ExecuteAsync(Lua* lua, const std::string& FuncName) {
std::lock_guard<std::mutex> lockGuard(lua->Lock); std::lock_guard<std::mutex> lockGuard(lua->Lock);
SafeExecution(lua,FuncName); SafeExecution(lua, FuncName);
} }
void CallAsync(Lua* lua,const std::string& Func,int U){ void CallAsync(Lua* lua, const std::string& Func, int U) {
lua->StopThread = false; DebugPrintTID();
lua->SetStopThread(false);
int D = 1000 / U; int D = 1000 / U;
while(!lua->StopThread){ while (!lua->GetStopThread()) {
ExecuteAsync(lua,Func); ExecuteAsync(lua, Func);
std::this_thread::sleep_for(std::chrono::milliseconds(D)); std::this_thread::sleep_for(std::chrono::milliseconds(D));
} }
} }
int lua_StopThread(lua_State *L){ int lua_StopThread(lua_State* L) {
GetScript(L)->StopThread = true; auto MaybeScript = GetScript(L);
Assert(MaybeScript.has_value());
// ugly, but whatever, this is safe as fuck
MaybeScript.value().get().SetStopThread(true);
return 0; return 0;
} }
int lua_CreateThread(lua_State *L){ int lua_CreateThread(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
if(Args > 1){ if (Args > 1) {
if(lua_isstring(L,1)) { if (lua_isstring(L, 1)) {
std::string STR = lua_tostring(L,1); std::string STR = lua_tostring(L, 1);
if(lua_isinteger(L,2) || lua_isnumber(L,2)){ if (lua_isinteger(L, 2) || lua_isnumber(L, 2)) {
int U = int(lua_tointeger(L,2)); int U = int(lua_tointeger(L, 2));
if(U > 0 && U < 501){ if (U > 0 && U < 501) {
std::thread t1(CallAsync,GetScript(L),STR,U); auto MaybeScript = GetScript(L);
Assert(MaybeScript.has_value());
Lua& Script = MaybeScript.value();
std::thread t1(CallAsync, &Script, STR, U);
t1.detach(); t1.detach();
}else SendError(L,Sec("CreateThread wrong argument [2] number must be between 1 and 500")); } else
}else SendError(L,Sec("CreateThread wrong argument [2] need number")); SendError(L, Sec("CreateThread wrong argument [2] number must be between 1 and 500"));
}else SendError(L,Sec("CreateThread wrong argument [1] need string")); } else
}else SendError(L,Sec("CreateThread not enough arguments")); SendError(L, Sec("CreateThread wrong argument [2] need number"));
} else
SendError(L, Sec("CreateThread wrong argument [1] need string"));
} else
SendError(L, Sec("CreateThread not enough arguments"));
return 0; return 0;
} }
int lua_Sleep(lua_State *L){ int lua_Sleep(lua_State* L) {
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int t = int(lua_tonumber(L, 1)); int t = int(lua_tonumber(L, 1));
std::this_thread::sleep_for(std::chrono::milliseconds(t)); std::this_thread::sleep_for(std::chrono::milliseconds(t));
}else{ } else {
SendError(L,Sec("Sleep not enough arguments")); SendError(L, Sec("Sleep not enough arguments"));
return 0; return 0;
} }
return 1; return 1;
} }
Client* GetClient(int ID){ Client* GetClient(int ID) {
for(Client*c : CI->Clients) { for (Client* c : CI->Clients) {
if(c != nullptr && c->GetID() == ID)return c; if (c != nullptr && c->GetID() == ID)
return c;
} }
return nullptr; return nullptr;
} }
int lua_isConnected(lua_State *L){ int lua_isConnected(lua_State* L) {
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1)); int ID = int(lua_tonumber(L, 1));
Client*c = GetClient(ID); Client* c = GetClient(ID);
if(c != nullptr)lua_pushboolean(L, c->isConnected); if (c != nullptr)
else return 0; lua_pushboolean(L, c->isConnected);
}else{ else
SendError(L,Sec("isConnected not enough arguments")); return 0;
} else {
SendError(L, Sec("isConnected not enough arguments"));
return 0; return 0;
} }
return 1; return 1;
} }
int lua_GetPlayerName(lua_State *L){ int lua_GetPlayerName(lua_State* L) {
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1)); int ID = int(lua_tonumber(L, 1));
Client*c = GetClient(ID); Client* c = GetClient(ID);
if(c != nullptr)lua_pushstring(L, c->GetName().c_str()); if (c != nullptr)
else return 0; lua_pushstring(L, c->GetName().c_str());
}else{ else
SendError(L,Sec("GetPlayerName not enough arguments")); return 0;
} else {
SendError(L, Sec("GetPlayerName not enough arguments"));
return 0; return 0;
} }
return 1; return 1;
} }
int lua_GetPlayerCount(lua_State *L){ int lua_GetPlayerCount(lua_State* L) {
lua_pushinteger(L, CI->Size()); lua_pushinteger(L, CI->Size());
return 1; return 1;
} }
int lua_GetDID(lua_State *L){ int lua_GetDID(lua_State* L) {
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1)); int ID = int(lua_tonumber(L, 1));
Client*c = GetClient(ID); Client* c = GetClient(ID);
if(c != nullptr)lua_pushstring(L, c->GetDID().c_str()); if (c != nullptr)
else return 0; lua_pushstring(L, c->GetDID().c_str());
}else{ else
SendError(L,Sec("GetDID not enough arguments")); return 0;
} else {
SendError(L, Sec("GetDID not enough arguments"));
return 0; return 0;
} }
return 1; return 1;
} }
int lua_GetAllPlayers(lua_State *L){ int lua_GetAllPlayers(lua_State* L) {
lua_newtable(L); lua_newtable(L);
int i = 1; int i = 1;
for (Client *c : CI->Clients) { for (Client* c : CI->Clients) {
if(c == nullptr)continue; if (c == nullptr)
continue;
lua_pushinteger(L, c->GetID()); lua_pushinteger(L, c->GetID());
lua_pushstring(L, c->GetName().c_str()); lua_pushstring(L, c->GetName().c_str());
lua_settable(L,-3); lua_settable(L, -3);
i++; i++;
} }
if(CI->Clients.empty())return 0; if (CI->Clients.empty())
return 0;
return 1; return 1;
} }
int lua_GetCars(lua_State *L){ int lua_GetCars(lua_State* L) {
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1)); int ID = int(lua_tonumber(L, 1));
Client*c = GetClient(ID); Client* c = GetClient(ID);
if(c != nullptr){ if (c != nullptr) {
int i = 1; int i = 1;
for (VData*v : c->GetAllCars()) { for (VData* v : c->GetAllCars()) {
if(v != nullptr) { if (v != nullptr) {
lua_pushinteger(L, v->ID); lua_pushinteger(L, v->ID);
lua_pushstring(L, v->Data.substr(3).c_str()); lua_pushstring(L, v->Data.substr(3).c_str());
lua_settable(L, -3); lua_settable(L, -3);
i++; i++;
} }
} }
if(c->GetAllCars().empty())return 0; if (c->GetAllCars().empty())
}else return 0; return 0;
}else{ } else
SendError(L,Sec("GetPlayerVehicles not enough arguments")); return 0;
} else {
SendError(L, Sec("GetPlayerVehicles not enough arguments"));
return 0; return 0;
} }
return 1; return 1;
} }
int lua_dropPlayer(lua_State *L){ int lua_dropPlayer(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
if(lua_isnumber(L,1)){ if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1)); int ID = int(lua_tonumber(L, 1));
Client*c = GetClient(ID); Client* c = GetClient(ID);
if(c == nullptr)return 0; if (c == nullptr)
if(c->GetRole() == Sec("MDEV"))return 0; return 0;
if (c->GetRole() == Sec("MDEV"))
return 0;
std::string Reason; std::string Reason;
if(Args > 1 && lua_isstring(L,2)){ if (Args > 1 && lua_isstring(L, 2)) {
Reason = std::string(Sec(" Reason : "))+lua_tostring(L,2); Reason = std::string(Sec(" Reason : ")) + lua_tostring(L, 2);
} }
Respond(c,"C:Server:You have been Kicked from the server! " + Reason,true); Respond(c, "C:Server:You have been Kicked from the server! " + Reason, true);
c->SetStatus(-2); c->SetStatus(-2);
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
}else SendError(L,Sec("DropPlayer not enough arguments")); } else
SendError(L, Sec("DropPlayer not enough arguments"));
return 0; return 0;
} }
int lua_sendChat(lua_State *L){ int lua_sendChat(lua_State* L) {
if(lua_isinteger(L,1) || lua_isnumber(L,1)){ if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) {
if(lua_isstring(L,2)){ if (lua_isstring(L, 2)) {
int ID = int(lua_tointeger(L,1)); int ID = int(lua_tointeger(L, 1));
if(ID == -1){ if (ID == -1) {
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
SendToAll(nullptr, Packet, true, true);
} else {
Client* c = GetClient(ID);
if (c != nullptr) {
if (!c->isSynced)
return 0;
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2)); std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
SendToAll(nullptr,Packet,true,true);
}else{
Client*c = GetClient(ID);
if(c != nullptr) {
if(!c->isSynced)return 0;
std::string Packet ="C:Server: " + std::string(lua_tostring(L, 2));
Respond(c, Packet, true); Respond(c, Packet, true);
}else SendError(L,Sec("SendChatMessage invalid argument [1] invalid ID")); } else
SendError(L, Sec("SendChatMessage invalid argument [1] invalid ID"));
} }
}else SendError(L,Sec("SendChatMessage invalid argument [2] expected string")); } else
}else SendError(L,Sec("SendChatMessage invalid argument [1] expected number")); SendError(L, Sec("SendChatMessage invalid argument [2] expected string"));
} else
SendError(L, Sec("SendChatMessage invalid argument [1] expected number"));
return 0; return 0;
} }
int lua_RemoveVehicle(lua_State *L){ int lua_RemoveVehicle(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
if(Args != 2){ if (Args != 2) {
SendError(L,Sec("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args)); SendError(L, Sec("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args));
return 0; return 0;
} }
if((lua_isinteger(L,1) || lua_isnumber(L,1)) && (lua_isinteger(L,2) || lua_isnumber(L,2))){ if ((lua_isinteger(L, 1) || lua_isnumber(L, 1)) && (lua_isinteger(L, 2) || lua_isnumber(L, 2))) {
int PID = int(lua_tointeger(L,1)); int PID = int(lua_tointeger(L, 1));
int VID = int(lua_tointeger(L,2)); int VID = int(lua_tointeger(L, 2));
Client *c = GetClient(PID); Client* c = GetClient(PID);
if(c == nullptr){ if (c == nullptr) {
SendError(L,Sec("RemoveVehicle invalid Player ID")); SendError(L, Sec("RemoveVehicle invalid Player ID"));
return 0; return 0;
} }
if(c->GetRole() == "MDEV")return 0; if (c->GetRole() == "MDEV")
if(!c->GetCarData(VID).empty()){ return 0;
std::string Destroy = "Od:" + std::to_string(PID)+"-"+std::to_string(VID); if (!c->GetCarData(VID).empty()) {
SendToAll(nullptr,Destroy,true,true); std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID);
SendToAll(nullptr, Destroy, true, true);
c->DeleteCar(VID); c->DeleteCar(VID);
} }
}else SendError(L,Sec("RemoveVehicle invalid argument expected number")); } else
SendError(L, Sec("RemoveVehicle invalid argument expected number"));
return 0; return 0;
} }
int lua_HWID(lua_State *L){ int lua_HWID(lua_State* L) {
lua_pushinteger(L, -1); lua_pushinteger(L, -1);
return 1; return 1;
} }
int lua_RemoteEvent(lua_State *L){ int lua_RemoteEvent(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
if(Args != 3){ if (Args != 3) {
SendError(L,Sec("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args)); SendError(L, Sec("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args));
return 0; return 0;
} }
if(!lua_isnumber(L,1)){ if (!lua_isnumber(L, 1)) {
SendError(L,Sec("TriggerClientEvent invalid argument [1] expected number")); SendError(L, Sec("TriggerClientEvent invalid argument [1] expected number"));
return 0; return 0;
} }
if(!lua_isstring(L,2)){ if (!lua_isstring(L, 2)) {
SendError(L,Sec("TriggerClientEvent invalid argument [2] expected string")); SendError(L, Sec("TriggerClientEvent invalid argument [2] expected string"));
return 0; return 0;
} }
if(!lua_isstring(L,3)){ if (!lua_isstring(L, 3)) {
SendError(L,Sec("TriggerClientEvent invalid argument [3] expected string")); SendError(L, Sec("TriggerClientEvent invalid argument [3] expected string"));
return 0; return 0;
} }
int ID = int(lua_tointeger(L,1)); int ID = int(lua_tointeger(L, 1));
std::string Packet = "E:" + std::string(lua_tostring(L,2)) + ":" + std::string(lua_tostring(L,3)); std::string Packet = "E:" + std::string(lua_tostring(L, 2)) + ":" + std::string(lua_tostring(L, 3));
if(ID == -1)SendToAll(nullptr,Packet,true,true); if (ID == -1)
else{ SendToAll(nullptr, Packet, true, true);
Client *c = GetClient(ID); else {
if(c == nullptr){ Client* c = GetClient(ID);
SendError(L,Sec("TriggerClientEvent invalid Player ID")); if (c == nullptr) {
SendError(L, Sec("TriggerClientEvent invalid Player ID"));
return 0; return 0;
} }
Respond(c,Packet,true); Respond(c, Packet, true);
} }
return 0; return 0;
} }
int lua_ServerExit(lua_State *L){ int lua_ServerExit(lua_State*) {
exit(0); exit(0);
} }
int lua_Set(lua_State *L){ int lua_Set(lua_State* L) {
int Args = lua_gettop(L); int Args = lua_gettop(L);
if(Args != 2){ if (Args != 2) {
SendError(L,Sec("set invalid argument count expected 2 got ") + std::to_string(Args)); SendError(L, Sec("set invalid argument count expected 2 got ") + std::to_string(Args));
return 0; return 0;
} }
if(!lua_isnumber(L,1)){ if (!lua_isnumber(L, 1)) {
SendError(L,Sec("set invalid argument [1] expected number")); SendError(L, Sec("set invalid argument [1] expected number"));
return 0; return 0;
} }
Lua* Src = GetScript(L); auto MaybeSrc = GetScript(L);
std::string Name; std::string Name;
if(Src == nullptr)Name = Sec("Console"); if (!MaybeSrc.has_value()) {
else Name = Src->GetPluginName(); Name = Sec("_Console");
int C = int(lua_tointeger(L,1)); } else {
switch(C){ Name = MaybeSrc.value().get().GetPluginName();
case 0: //debug
if(lua_isboolean(L,2)){
Debug = lua_toboolean(L,2);
info(Name + Sec(" | Debug -> ") + (Debug?"true":"false"));
} }
else SendError(L,Sec("set invalid argument [2] expected boolean for ID : 0")); int C = int(lua_tointeger(L, 1));
switch (C) {
case 0: //debug
if (lua_isboolean(L, 2)) {
Debug = lua_toboolean(L, 2);
info(Name + Sec(" | Debug -> ") + (Debug ? "true" : "false"));
} else
SendError(L, Sec("set invalid argument [2] expected boolean for ID : 0"));
break; break;
case 1: //private case 1: //private
if(lua_isboolean(L,2)){ if (lua_isboolean(L, 2)) {
Private = lua_toboolean(L,2); Private = lua_toboolean(L, 2);
info(Name + Sec(" | Private -> ") + (Private?"true":"false")); info(Name + Sec(" | Private -> ") + (Private ? "true" : "false"));
} } else
else SendError(L,Sec("set invalid argument [2] expected boolean for ID : 1")); SendError(L, Sec("set invalid argument [2] expected boolean for ID : 1"));
break; break;
case 2: //max cars case 2: //max cars
if(lua_isnumber(L,2)){ if (lua_isnumber(L, 2)) {
MaxCars = int(lua_tointeger(L,2)); MaxCars = int(lua_tointeger(L, 2));
info(Name + Sec(" | MaxCars -> ") + std::to_string(MaxCars)); info(Name + Sec(" | MaxCars -> ") + std::to_string(MaxCars));
} } else
else SendError(L,Sec("set invalid argument [2] expected number for ID : 2")); SendError(L, Sec("set invalid argument [2] expected number for ID : 2"));
break; break;
case 3: //max players case 3: //max players
if(lua_isnumber(L,2)){ if (lua_isnumber(L, 2)) {
MaxPlayers = int(lua_tointeger(L,2)); MaxPlayers = int(lua_tointeger(L, 2));
info(Name + Sec(" | MaxPlayers -> ") + std::to_string(MaxPlayers)); info(Name + Sec(" | MaxPlayers -> ") + std::to_string(MaxPlayers));
} } else
else SendError(L,Sec("set invalid argument [2] expected number for ID : 3")); SendError(L, Sec("set invalid argument [2] expected number for ID : 3"));
break; break;
case 4: //Map case 4: //Map
if(lua_isstring(L,2)){ if (lua_isstring(L, 2)) {
MapName = lua_tostring(L,2); MapName = lua_tostring(L, 2);
info(Name + Sec(" | MapName -> ") + MapName); info(Name + Sec(" | MapName -> ") + MapName);
} } else
else SendError(L,Sec("set invalid argument [2] expected string for ID : 4")); SendError(L, Sec("set invalid argument [2] expected string for ID : 4"));
break; break;
case 5: //Name case 5: //Name
if(lua_isstring(L,2)){ if (lua_isstring(L, 2)) {
ServerName = lua_tostring(L,2); ServerName = lua_tostring(L, 2);
info(Name + Sec(" | ServerName -> ") + ServerName); info(Name + Sec(" | ServerName -> ") + ServerName);
} } else
else SendError(L,Sec("set invalid argument [2] expected string for ID : 5")); SendError(L, Sec("set invalid argument [2] expected string for ID : 5"));
break; break;
case 6: //Desc case 6: //Desc
if(lua_isstring(L,2)){ if (lua_isstring(L, 2)) {
ServerDesc = lua_tostring(L,2); ServerDesc = lua_tostring(L, 2);
info(Name + Sec(" | ServerDesc -> ") + ServerDesc); info(Name + Sec(" | ServerDesc -> ") + ServerDesc);
} } else
else SendError(L,Sec("set invalid argument [2] expected string for ID : 6")); SendError(L, Sec("set invalid argument [2] expected string for ID : 6"));
break; break;
default: default:
warn(Sec("Invalid config ID : ") + std::to_string(C)); warn(Sec("Invalid config ID : ") + std::to_string(C));
@ -445,123 +515,149 @@ int lua_Set(lua_State *L){
return 0; return 0;
} }
extern "C" { extern "C" {
int lua_Print(lua_State *L) { int lua_Print(lua_State* L) {
int Arg = lua_gettop(L); int Arg = lua_gettop(L);
for (int i = 1; i <= Arg; i++){ for (int i = 1; i <= Arg; i++) {
ConsoleOut(lua_tostring(L, i) + std::string("\n")); ConsoleOut(lua_tostring(L, i) + std::string("\n"));
} }
return 0; return 0;
} }
} }
void Lua::Init(){ Lua::Lua(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote, bool Console)
luaL_openlibs(luaState); : luaState(luaL_newstate()) {
lua_register(luaState,"TriggerGlobalEvent",lua_TriggerEventG); Assert(luaState);
lua_register(luaState,"TriggerLocalEvent",lua_TriggerEventL); if (!PluginName.empty()) {
lua_register(luaState,"TriggerClientEvent",lua_RemoteEvent); SetPluginName(PluginName);
lua_register(luaState,"GetPlayerCount",lua_GetPlayerCount); }
lua_register(luaState,"isPlayerConnected",lua_isConnected); if (!FileName.empty()) {
lua_register(luaState,"RegisterEvent",lua_RegisterEvent); SetFileName(FileName);
lua_register(luaState,"GetPlayerName",lua_GetPlayerName); }
lua_register(luaState,"RemoveVehicle",lua_RemoveVehicle); SetLastWrite(LastWrote);
lua_register(luaState,"GetPlayerDiscordID",lua_GetDID); _Console = Console;
lua_register(luaState,"GetPlayerVehicles",lua_GetCars); Init();
lua_register(luaState,"CreateThread",lua_CreateThread);
lua_register(luaState,"SendChatMessage",lua_sendChat);
lua_register(luaState,"GetPlayers",lua_GetAllPlayers);
lua_register(luaState,"StopThread",lua_StopThread);
lua_register(luaState,"DropPlayer",lua_dropPlayer);
lua_register(luaState,"GetPlayerHWID",lua_HWID);
lua_register(luaState,"exit",lua_ServerExit);
lua_register(luaState,"Sleep",lua_Sleep);
lua_register(luaState,"print",lua_Print);
lua_register(luaState,"Set",lua_Set);
if(!Console)Reload();
} }
void Lua::Execute(const std::string& Command){
if(ConsoleCheck(luaState,luaL_dostring(luaState,Command.c_str()))){ Lua::Lua(bool Console)
: luaState(luaL_newstate()) {
_Console = Console;
Init();
}
void Lua::Execute(const std::string& Command) {
if (ConsoleCheck(luaState, luaL_dostring(luaState, Command.c_str()))) {
lua_settop(luaState, 0); lua_settop(luaState, 0);
} }
} }
void Lua::Reload(){ void Lua::Reload() {
if(CheckLua(luaState,luaL_dofile(luaState,FileName.c_str()))){ if (CheckLua(luaState, luaL_dofile(luaState, _FileName.c_str()))) {
CallFunction(this,Sec("onInit"), nullptr); CallFunction(this, Sec("onInit"), nullptr);
} }
} }
char* Lua::GetOrigin(){ std::string Lua::GetOrigin() {
std::string T = GetFileName().substr(GetFileName().find('\\')); return GetFileName().substr(GetFileName().find('\\'));
char* Data = new char[T.size()];
ZeroMemory(Data,T.size());
memcpy_s(Data,T.size(),T.c_str(),T.size());
return Data;
} }
int CallFunction(Lua*lua,const std::string& FuncName,LuaArg* Arg){
lua_State*luaState = lua->GetState(); int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> Arg) {
lua_State* luaState = lua->GetState();
lua_getglobal(luaState, FuncName.c_str()); lua_getglobal(luaState, FuncName.c_str());
if(lua_isfunction(luaState, -1)) { if (lua_isfunction(luaState, -1)) {
int Size = 0; int Size = 0;
if(Arg != nullptr){ if (Arg != nullptr) {
Size = int(Arg->args.size()); Size = int(Arg->args.size());
Arg->PushArgs(luaState); Arg->PushArgs(luaState);
delete Arg;
Arg = nullptr;
} }
int R = 0; std::string Origin = lua->GetOrigin();
char* Origin = lua->GetOrigin(); int R = lua_pcall(luaState, Size, 1, 0);
__try{ if (CheckLua(luaState, R)) {
R = lua_pcall(luaState, Size, 1, 0);
if (CheckLua(luaState, R)){
if (lua_isnumber(luaState, -1)) { if (lua_isnumber(luaState, -1)) {
return int(lua_tointeger(luaState, -1)); return int(lua_tointeger(luaState, -1));
} }
} }
}__except(Handle(GetExceptionInformation(),Origin)){}
delete [] Origin;
} }
ClearStack(luaState); ClearStack(luaState);
return 0; return 0;
} }
void Lua::SetPluginName(const std::string&Name){ void Lua::SetPluginName(const std::string& Name) {
PluginName = Name; _PluginName = Name;
} }
void Lua::SetFileName(const std::string&Name){ void Lua::SetFileName(const std::string& Name) {
FileName = Name; _FileName = Name;
} }
void Lua::RegisterEvent(const std::string& Event,const std::string& FunctionName){ void Lua::Init() {
RegisteredEvents.insert(std::make_pair(Event,FunctionName)); Assert(luaState);
luaL_openlibs(luaState);
lua_register(luaState, "TriggerGlobalEvent", lua_TriggerEventG);
lua_register(luaState, "TriggerLocalEvent", lua_TriggerEventL);
lua_register(luaState, "TriggerClientEvent", lua_RemoteEvent);
lua_register(luaState, "GetPlayerCount", lua_GetPlayerCount);
lua_register(luaState, "isPlayerConnected", lua_isConnected);
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, "CreateThread", lua_CreateThread);
lua_register(luaState, "SendChatMessage", lua_sendChat);
lua_register(luaState, "GetPlayers", lua_GetAllPlayers);
lua_register(luaState, "StopThread", lua_StopThread);
lua_register(luaState, "DropPlayer", lua_dropPlayer);
lua_register(luaState, "GetPlayerHWID", lua_HWID);
lua_register(luaState, "exit", lua_ServerExit);
lua_register(luaState, "Sleep", lua_Sleep);
lua_register(luaState, "print", lua_Print);
lua_register(luaState, "Set", lua_Set);
if (!_Console)
Reload();
} }
void Lua::UnRegisterEvent(const std::string&Event){
for(const std::pair<std::string,std::string>& a : RegisteredEvents){ void Lua::RegisterEvent(const std::string& Event, const std::string& FunctionName) {
if(a.first == Event) { _RegisteredEvents.insert(std::make_pair(Event, FunctionName));
RegisteredEvents.erase(a); }
void Lua::UnRegisterEvent(const std::string& Event) {
for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
if (a.first == Event) {
_RegisteredEvents.erase(a);
break; break;
} }
} }
} }
bool Lua::IsRegistered(const std::string&Event){ bool Lua::IsRegistered(const std::string& Event) {
for(const std::pair<std::string,std::string>& a : RegisteredEvents){ for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
if(a.first == Event)return true; if (a.first == Event)
return true;
} }
return false; return false;
} }
std::string Lua::GetRegistered(const std::string&Event){ std::string Lua::GetRegistered(const std::string& Event) const {
for(const std::pair<std::string,std::string>& a : RegisteredEvents){ for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
if(a.first == Event)return a.second; if (a.first == Event)
return a.second;
} }
return ""; return "";
} }
std::string Lua::GetFileName(){ std::string Lua::GetFileName() const {
return FileName; return _FileName;
} }
std::string Lua::GetPluginName(){ std::string Lua::GetPluginName() const {
return PluginName; return _PluginName;
} }
lua_State* Lua::GetState(){ lua_State* Lua::GetState() {
return luaState; return luaState;
} }
void Lua::SetLastWrite(fs::file_time_type time){
LastWrote = time; const lua_State* Lua::GetState() const {
return luaState;
} }
fs::file_time_type Lua::GetLastWrite(){
return LastWrote; void Lua::SetLastWrite(fs::file_time_type time) {
_LastWrote = time;
}
fs::file_time_type Lua::GetLastWrite() {
return _LastWrote;
}
Lua::~Lua() {
info("closing lua state");
lua_close(luaState);
} }

View File

@ -8,23 +8,50 @@
#include "Logger.h" #include "Logger.h"
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <cstring>
#include <algorithm>
#include "UnixCompat.h"
struct Hold{ struct Hold{
SOCKET TCPSock{}; SOCKET TCPSock{};
bool Done = false; bool Done = false;
}; };
bool Send(SOCKET TCPSock,std::string Data){ bool Send(SOCKET TCPSock,std::string Data){
#ifdef WIN32
int BytesSent; int BytesSent;
BytesSent = send(TCPSock, Data.c_str(), int(Data.size()), 0); 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(); Data.clear();
if (BytesSent <= 0)return false; if (BytesSent <= 0)return false;
return true; return true;
} }
std::string Rcv(SOCKET TCPSock){ std::string Rcv(SOCKET TCPSock){
char buf[6768]; uint32_t RealSize;
int len = 6768; int64_t BytesRcv = recv(TCPSock, &RealSize, sizeof(RealSize), 0);
ZeroMemory(buf, len); if (BytesRcv != sizeof(RealSize)) {
int BytesRcv = recv(TCPSock, buf, len,0); error(std::string(Sec("invalid packet: expected 4, got ")) + std::to_string(BytesRcv));
if (BytesRcv <= 0)return ""; 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); return std::string(buf);
} }
std::string GetRole(const std::string &DID){ std::string GetRole(const std::string &DID){
@ -86,17 +113,21 @@ std::string GenerateM(RSA*key){
} }
void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){ void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){
Assert(S);
Assert(Skey);
S->TCPSock = TCPSock; S->TCPSock = TCPSock;
std::thread Timeout(Check,S); std::thread Timeout(Check,S);
Timeout.detach(); Timeout.detach();
std::string Name,DID,Role; std::string Name,DID,Role;
if(!Send(TCPSock,GenerateM(Skey))){ if(!Send(TCPSock,GenerateM(Skey))){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
std::string msg = Rcv(TCPSock); std::string msg = Rcv(TCPSock);
auto Keys = Parse(msg); auto Keys = Parse(msg);
if(!Send(TCPSock,RSA_E("HC",Keys.second,Keys.first))){ if(!Send(TCPSock,RSA_E("HC",Keys.second,Keys.first))){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
@ -108,26 +139,31 @@ void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){
if(Ver.size() > 3 && Ver.substr(0,2) == Sec("VC")){ if(Ver.size() > 3 && Ver.substr(0,2) == Sec("VC")){
Ver = Ver.substr(2); Ver = Ver.substr(2);
if(Ver.length() > 4 || Ver != GetCVer()){ if(Ver.length() > 4 || Ver != GetCVer()){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
}else{ }else{
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
Res = RSA_D(Res,Skey); Res = RSA_D(Res,Skey);
if(Res.size() < 3 || Res.substr(0,2) != Sec("NR")) { if(Res.size() < 3 || Res.substr(0,2) != Sec("NR")) {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
if(Res.find(':') == std::string::npos){ if(Res.find(':') == std::string::npos){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
Name = Res.substr(2,Res.find(':')-2); Name = Res.substr(2,Res.find(':')-2);
DID = Res.substr(Res.find(':')+1); DID = Res.substr(Res.find(':')+1);
Role = GetRole(DID); Role = GetRole(DID);
if(Role.empty() || Role.find(Sec("Error")) != -1){ if(Role.empty() || Role.find(Sec("Error")) != std::string::npos){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
return; return;
} }
@ -135,6 +171,7 @@ void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){
for(Client*c: CI->Clients){ for(Client*c: CI->Clients){
if(c != nullptr){ if(c != nullptr){
if(c->GetDID() == DID){ if(c->GetDID() == DID){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
c->SetStatus(-2); c->SetStatus(-2);
break; break;
@ -142,23 +179,40 @@ void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){
} }
} }
if(Role == Sec("MDEV") || CI->Size() < Max()){ if(Role == Sec("MDEV") || CI->Size() < Max()){
debug("Identification success");
CreateClient(TCPSock,Name,DID,Role); CreateClient(TCPSock,Name,DID,Role);
}else closesocket(TCPSock); } else {
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock);
}
} }
void Identify(SOCKET TCPSock){ void Identify(SOCKET TCPSock){
auto* S = new Hold; auto* S = new Hold;
RSA*Skey = GenKey(); 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{ __try{
#endif // WIN32
Identification(TCPSock,S,Skey); Identification(TCPSock,S,Skey);
#ifdef WIN32
}__except(1){ }__except(1){
if(TCPSock != -1){ if(TCPSock != -1){
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(TCPSock); closesocket(TCPSock);
} }
} }
#endif // WIN32
delete Skey; delete Skey;
delete S; delete S;
} }
void TCPServerMain(){ void TCPServerMain(){
DebugPrintTID();
#ifdef WIN32
WSADATA wsaData; WSADATA wsaData;
if (WSAStartup(514, &wsaData)){ if (WSAStartup(514, &wsaData)){
error(Sec("Can't start Winsock!")); error(Sec("Can't start Winsock!"));
@ -195,4 +249,39 @@ void TCPServerMain(){
closesocket(client); closesocket(client);
WSACleanup(); WSACleanup();
#else // unix
// wondering why we need slightly different implementations of this?
// ask ms.
SOCKET client, Listener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sockaddr_in addr{};
addr.sin_addr.s_addr = INADDR_ANY;
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)));
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
}
if(Listener == -1){
error(Sec("Invalid listening socket"));
return;
}
if(listen(Listener,SOMAXCONN)){
error(Sec("listener failed ")+ std::string(strerror(errno)));
return;
}
info(Sec("Vehicle event network online"));
do{
client = accept(Listener, nullptr, nullptr);
if(client == -1){
warn(Sec("Got an invalid client socket on connect! Skipping..."));
continue;
}
std::thread ID(Identify,client);
ID.detach();
}while(client);
debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__));
closesocket(client);
#endif // WIN32
} }

View File

@ -7,8 +7,10 @@
#include "Settings.h" #include "Settings.h"
#include "Network.h" #include "Network.h"
#include "Logger.h" #include "Logger.h"
#include "UnixCompat.h"
#include <sstream> #include <sstream>
int FC(const std::string& s,const std::string& p,int n) { int FC(const std::string& s,const std::string& p,int n) {
auto i = s.find(p); auto i = s.find(p);
int j; int j;
@ -19,6 +21,7 @@ int FC(const std::string& s,const std::string& p,int n) {
else return -1; else return -1;
} }
void Apply(Client*c,int VID,const std::string& pckt){ void Apply(Client*c,int VID,const std::string& pckt){
Assert(c);
std::string Packet = pckt; std::string Packet = pckt;
std::string VD = c->GetCarData(VID); std::string VD = c->GetCarData(VID);
Packet = Packet.substr(FC(Packet, ",", 2) + 1); Packet = Packet.substr(FC(Packet, ",", 2) + 1);
@ -29,6 +32,7 @@ void Apply(Client*c,int VID,const std::string& pckt){
} }
void VehicleParser(Client*c,const std::string& Pckt){ void VehicleParser(Client*c,const std::string& Pckt){
Assert(c);
if(c == nullptr || Pckt.length() < 4)return; if(c == nullptr || Pckt.length() < 4)return;
std::string Packet = Pckt; std::string Packet = Pckt;
char Code = Packet.at(1); char Code = Packet.at(1);
@ -43,7 +47,8 @@ void VehicleParser(Client*c,const std::string& Pckt){
Packet = "Os:"+c->GetRole()+":"+c->GetName()+":"+std::to_string(c->GetID())+"-"+std::to_string(CarID)+Packet.substr(4); Packet = "Os:"+c->GetRole()+":"+c->GetName()+":"+std::to_string(c->GetID())+"-"+std::to_string(CarID)+Packet.substr(4);
if(c->GetCarCount() >= MaxCars || if(c->GetCarCount() >= MaxCars ||
TriggerLuaEvent(Sec("onVehicleSpawn"),false,nullptr, TriggerLuaEvent(Sec("onVehicleSpawn"),false,nullptr,
new LuaArg{{c->GetID(),CarID,Packet.substr(3)}},true)){ std::unique_ptr<LuaArg>(new LuaArg{{c->GetID(),CarID,Packet.substr(3)}}),
true)){
Respond(c,Packet,true); Respond(c,Packet,true);
std::string Destroy = "Od:" + std::to_string(c->GetID())+"-"+std::to_string(CarID); std::string Destroy = "Od:" + std::to_string(c->GetID())+"-"+std::to_string(CarID);
Respond(c,Destroy,true); Respond(c,Destroy,true);
@ -63,7 +68,8 @@ void VehicleParser(Client*c,const std::string& Pckt){
} }
if(PID != -1 && VID != -1 && PID == c->GetID()){ if(PID != -1 && VID != -1 && PID == c->GetID()){
if(!TriggerLuaEvent(Sec("onVehicleEdited"),false,nullptr, if(!TriggerLuaEvent(Sec("onVehicleEdited"),false,nullptr,
new LuaArg{{c->GetID(),VID,Packet.substr(3)}},true)) { std::unique_ptr<LuaArg>(new LuaArg{{c->GetID(),VID,Packet.substr(3)}}),
true)) {
SendToAll(c, Packet, false, true); SendToAll(c, Packet, false, true);
Apply(c,VID,Packet); Apply(c,VID,Packet);
}else{ }else{
@ -83,7 +89,7 @@ void VehicleParser(Client*c,const std::string& Pckt){
if(PID != -1 && VID != -1 && PID == c->GetID()){ if(PID != -1 && VID != -1 && PID == c->GetID()){
SendToAll(nullptr,Packet,true,true); SendToAll(nullptr,Packet,true,true);
TriggerLuaEvent(Sec("onVehicleDeleted"),false,nullptr, TriggerLuaEvent(Sec("onVehicleDeleted"),false,nullptr,
new LuaArg{{c->GetID(),VID}},false); std::unique_ptr<LuaArg>(new LuaArg{{c->GetID(),VID}}),false);
c->DeleteCar(VID); c->DeleteCar(VID);
debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID)); debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID));
} }
@ -92,16 +98,18 @@ void VehicleParser(Client*c,const std::string& Pckt){
SendToAll(c,Packet,false,true); SendToAll(c,Packet,false,true);
return; return;
default: default:
AssertNotReachable();
return; return;
} }
} }
void SyncClient(Client*c){ void SyncClient(Client*c){
Assert(c);
if(c->isSynced)return; if(c->isSynced)return;
c->isSynced = true; c->isSynced = true;
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
Respond(c,Sec("Sn")+c->GetName(),true); Respond(c,Sec("Sn")+c->GetName(),true);
SendToAll(c,Sec("JWelcome ")+c->GetName()+"!",false,true); SendToAll(c,Sec("JWelcome ")+c->GetName()+"!",false,true);
TriggerLuaEvent(Sec("onPlayerJoin"),false,nullptr,new LuaArg{{c->GetID()}},false); TriggerLuaEvent(Sec("onPlayerJoin"),false,nullptr,std::unique_ptr<LuaArg>(new LuaArg{{c->GetID()}}),false);
for (Client*client : CI->Clients) { for (Client*client : CI->Clients) {
if(client != nullptr){ if(client != nullptr){
if (client != c) { if (client != c) {
@ -116,13 +124,19 @@ void SyncClient(Client*c){
} }
info(c->GetName() + Sec(" is now synced!")); info(c->GetName() + Sec(" is now synced!"));
} }
void ParseVeh(Client*c, const std::string&Packet){ void ParseVeh(Client*c, const std::string& Packet){
Assert(c);
#ifdef WIN32
__try{ __try{
VehicleParser(c,Packet); VehicleParser(c,Packet);
}__except(Handle(GetExceptionInformation(),Sec("Vehicle Handler"))){} }__except(Handle(GetExceptionInformation(),Sec("Vehicle Handler"))){}
#else // unix
VehicleParser(c,Packet);
#endif // WIN32
} }
void HandleEvent(Client*c ,const std::string&Data){ void HandleEvent(Client*c ,const std::string&Data){
Assert(c);
std::stringstream ss(Data); std::stringstream ss(Data);
std::string t,Name; std::string t,Name;
int a = 0; int a = 0;
@ -132,7 +146,7 @@ void HandleEvent(Client*c ,const std::string&Data){
Name = t; Name = t;
break; break;
case 2: case 2:
TriggerLuaEvent(Name, false, nullptr,new LuaArg{{c->GetID(),t}},false); TriggerLuaEvent(Name, false, nullptr,std::unique_ptr<LuaArg>(new LuaArg{{c->GetID(),t}}),false);
break; break;
default: default:
break; break;
@ -143,7 +157,8 @@ void HandleEvent(Client*c ,const std::string&Data){
} }
void GlobalParser(Client*c, const std::string& Pack){ void GlobalParser(Client*c, const std::string& Pack){
static int lastRecv = 0; Assert(c);
[[maybe_unused]] static int lastRecv = 0;
if(Pack.empty() || c == nullptr)return; if(Pack.empty() || c == nullptr)return;
std::string Packet = Pack.substr(0,Pack.find(char(0))); std::string Packet = Pack.substr(0,Pack.find(char(0)));
std::string pct; std::string pct;
@ -157,7 +172,7 @@ void GlobalParser(Client*c, const std::string& Pack){
} }
switch (Code) { switch (Code) {
case 'P': case 'P': // initial connection
Respond(c, Sec("P") + std::to_string(c->GetID()),true); Respond(c, Sec("P") + std::to_string(c->GetID()),true);
SyncClient(c); SyncClient(c);
return; return;
@ -175,10 +190,11 @@ void GlobalParser(Client*c, const std::string& Pack){
SendToAll(c,Packet,false,true); SendToAll(c,Packet,false,true);
return; return;
case 'C': case 'C':
if(Packet.length() < 4 || Packet.find(':', 3) == -1)break; if(Packet.length() < 4 || Packet.find(':', 3) == std::string::npos)break;
if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,new LuaArg{ if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,
std::unique_ptr<LuaArg>(new LuaArg{
{c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1)} {c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1)}
},true))break; }),true))break;
SendToAll(nullptr, Packet, true, true); SendToAll(nullptr, Packet, true, true);
return; return;
case 'E': case 'E':
@ -189,8 +205,13 @@ void GlobalParser(Client*c, const std::string& Pack){
} }
} }
void GParser(Client*c, const std::string&Packet){ void GParser(Client*c, const std::string& Packet){
Assert(c);
#ifdef WIN32
__try{ __try{
GlobalParser(c, Packet); GlobalParser(c, Packet);
}__except(Handle(GetExceptionInformation(),Sec("Global Handler"))){} }__except(Handle(GetExceptionInformation(),Sec("Global Handler"))){}
#else
GlobalParser(c, Packet);
#endif // WIN32
} }

View File

@ -3,6 +3,7 @@
/// ///
#define CURL_STATICLIB #define CURL_STATICLIB
#include "Curl/curl.h" #include "Curl/curl.h"
#include "CustomAssert.h"
#include <iostream> #include <iostream>
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){ static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){
((std::string*)userp)->append((char*)contents, size * nmemb); ((std::string*)userp)->append((char*)contents, size * nmemb);
@ -13,6 +14,7 @@ std::string HttpRequest(const std::string& IP,int port){
CURLcode res; CURLcode res;
std::string readBuffer; std::string readBuffer;
curl = curl_easy_init(); curl = curl_easy_init();
Assert(curl);
if(curl) { if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
curl_easy_setopt(curl, CURLOPT_PORT, port); curl_easy_setopt(curl, CURLOPT_PORT, port);
@ -30,6 +32,7 @@ std::string PostHTTP(const std::string& IP,const std::string& Fields){
CURLcode res; CURLcode res;
std::string readBuffer; std::string readBuffer;
curl = curl_easy_init(); curl = curl_easy_init();
Assert(curl);
if(curl) { if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size());

View File

@ -24,6 +24,7 @@ int OpenID(){
return ID; return ID;
} }
void Respond(Client*c, const std::string& MSG, bool Rel){ void Respond(Client*c, const std::string& MSG, bool Rel){
Assert(c);
char C = MSG.at(0); char C = MSG.at(0);
if(Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E'){ if(Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E'){
if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG); if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG);
@ -31,6 +32,9 @@ void Respond(Client*c, const std::string& MSG, bool Rel){
}else UDPSend(c,MSG); }else UDPSend(c,MSG);
} }
void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){ void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){
if (!Self) {
Assert(c);
}
char C = Data.at(0); char C = Data.at(0);
for(Client*client : CI->Clients){ for(Client*client : CI->Clients){
if(client != nullptr) { if(client != nullptr) {
@ -55,6 +59,7 @@ void UpdatePlayers(){
SendToAll(nullptr, Packet,true,true); SendToAll(nullptr, Packet,true,true);
} }
void OnDisconnect(Client*c,bool kicked){ void OnDisconnect(Client*c,bool kicked){
Assert(c);
info(c->GetName() + Sec(" Connection Terminated")); info(c->GetName() + Sec(" Connection Terminated"));
if(c == nullptr)return; if(c == nullptr)return;
std::string Packet; std::string Packet;
@ -68,18 +73,19 @@ void OnDisconnect(Client*c,bool kicked){
Packet = Sec("L")+c->GetName()+Sec(" Left the server!"); Packet = Sec("L")+c->GetName()+Sec(" Left the server!");
SendToAll(c, Packet,false,true); SendToAll(c, Packet,false,true);
Packet.clear(); Packet.clear();
TriggerLuaEvent(Sec("onPlayerDisconnect"),false,nullptr,new LuaArg{{c->GetID()}},false); TriggerLuaEvent(Sec("onPlayerDisconnect"),false,nullptr,std::unique_ptr<LuaArg>(new LuaArg{{c->GetID()}}),false);
c->ClearCars(); c->ClearCars();
CI->RemoveClient(c); ///Removes the Client from existence CI->RemoveClient(c); ///Removes the Client from existence
} }
void OnConnect(Client*c){ void OnConnect(Client*c){
Assert(c);
info(Sec("Client connected")); info(Sec("Client connected"));
c->SetID(OpenID()); c->SetID(OpenID());
info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName()); info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName());
TriggerLuaEvent(Sec("onPlayerConnecting"),false,nullptr,new LuaArg{{c->GetID()}},false); TriggerLuaEvent(Sec("onPlayerConnecting"),false,nullptr,std::unique_ptr<LuaArg>(new LuaArg{{c->GetID()}}),false);
SyncResources(c); SyncResources(c);
if(c->GetStatus() < 0)return; if(c->GetStatus() < 0)return;
Respond(c,"M"+MapName,true); //Send the Map on connect Respond(c,"M"+MapName,true); //Send the Map on connect
info(c->GetName() + Sec(" : Connected")); info(c->GetName() + Sec(" : Connected"));
TriggerLuaEvent(Sec("onPlayerJoining"),false,nullptr,new LuaArg{{c->GetID()}},false); TriggerLuaEvent(Sec("onPlayerJoining"),false,nullptr,std::unique_ptr<LuaArg>(new LuaArg{{c->GetID()}}),false);
} }

View File

@ -30,6 +30,7 @@ void Monitor() {
} }
[[noreturn]]void Stat(){ [[noreturn]]void Stat(){
DebugPrintTID();
while(true){ while(true){
Monitor(); Monitor();
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));

View File

@ -1,102 +1,133 @@
/// ///
/// Created by Anonymous275 on 8/1/2020 /// Created by Anonymous275 on 8/1/2020
/// ///
#include "Security/Enc.h"
#include "Client.hpp" #include "Client.hpp"
#include "Settings.h"
#include "Logger.h" #include "Logger.h"
#include "Security/Enc.h"
#include "Settings.h"
#include "UnixCompat.h"
#include <fstream> #include <fstream>
void STCPSend(Client*c,std::string Data){ #ifdef __linux
if(c == nullptr)return; // 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 BytesSent;
BytesSent = send(c->GetTCPSock(), Data.c_str(), int(Data.size()), 0); 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(); Data.clear();
if (BytesSent == 0){ if (BytesSent == 0) {
if(c->GetStatus() > -1)c->SetStatus(-1); if (c->GetStatus() > -1)
}else if (BytesSent < 0) { c->SetStatus(-1);
if(c->GetStatus() > -1)c->SetStatus(-1); } else if (BytesSent < 0) {
if (c->GetStatus() > -1)
c->SetStatus(-1);
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
} }
} }
void SendFile(Client*c,const std::string&Name){ void SendFile(Client* c, const std::string& Name) {
info(c->GetName()+Sec(" requesting : ")+Name.substr(Name.find_last_of('/'))); Assert(c);
struct stat Info{}; info(c->GetName() + Sec(" requesting : ") + Name.substr(Name.find_last_of('/')));
if(stat(Name.c_str(), &Info) != 0){ struct stat Info {};
STCPSend(c,Sec("Cannot Open")); if (stat(Name.c_str(), &Info) != 0) {
STCPSend(c, Sec("Cannot Open"));
return; return;
} }
std::ifstream f(Name.c_str(), std::ios::binary); std::ifstream f(Name.c_str(), std::ios::binary);
f.seekg(0, std::ios_base::end); f.seekg(0, std::ios_base::end);
std::streampos fileSize = f.tellg(); std::streampos fileSize = f.tellg();
size_t Size = fileSize,Sent = 0,Diff; size_t Size = size_t(fileSize);
int Split = 64000; size_t Sent = 0;
while(c->GetStatus() > -1 && Sent < Size){ size_t Diff;
int64_t Split = 64000;
while (c->GetStatus() > -1 && Sent < Size) {
Diff = Size - Sent; Diff = Size - Sent;
if(Diff > Split){ if (Diff > size_t(Split)) {
std::string Data(Split,0); std::string Data(size_t(Split), 0);
f.seekg(Sent, std::ios_base::beg); f.seekg(int64_t(Sent), std::ios_base::beg);
f.read(&Data[0], Split); f.read(&Data[0], Split);
STCPSend(c,Data); STCPSend(c, Data);
Sent += Split; Sent += size_t(Split);
}else{ } else {
std::string Data(Diff,0); std::string Data(Diff, 0);
f.seekg(Sent, std::ios_base::beg); f.seekg(int64_t(Sent), std::ios_base::beg);
f.read(&Data[0], Diff); f.read(&Data[0], int64_t(Diff));
STCPSend(c,Data); STCPSend(c, Data);
Sent += Diff; Sent += Diff;
} }
} }
f.close(); f.close();
} }
void Parse(Client*c,const std::string&Packet){ void Parse(Client* c, const std::string& Packet) {
if(c == nullptr || Packet.empty())return; Assert(c);
char Code = Packet.at(0),SubCode = 0; if (c == nullptr || Packet.empty())
if(Packet.length() > 1)SubCode = Packet.at(1); return;
char Code = Packet.at(0), SubCode = 0;
if (Packet.length() > 1)
SubCode = Packet.at(1);
switch (Code) { switch (Code) {
case 'f': case 'f':
SendFile(c,Packet.substr(1)); SendFile(c, Packet.substr(1));
return; return;
case 'S': case 'S':
if(SubCode == 'R'){ if (SubCode == 'R') {
debug(Sec("Sending Mod Info")); debug(Sec("Sending Mod Info"));
std::string ToSend = FileList+FileSizes; std::string ToSend = FileList + FileSizes;
if(ToSend.empty())ToSend = "-"; if (ToSend.empty())
STCPSend(c,ToSend); ToSend = "-";
STCPSend(c, ToSend);
} }
return; return;
default: default:
return; return;
} }
} }
bool STCPRecv(Client*c){ bool STCPRecv(Client* c) {
if(c == nullptr)return false; Assert(c);
if (c == nullptr)
return false;
char buf[200]; char buf[200];
int len = 200; size_t len = 200;
ZeroMemory(buf, len); ZeroMemory(buf, len);
int BytesRcv = recv(c->GetTCPSock(), buf, len,0); int64_t BytesRcv = recv(c->GetTCPSock(), buf, len, 0);
if (BytesRcv == 0){ if (BytesRcv == 0) {
if(c->GetStatus() > -1)c->SetStatus(-1); if (c->GetStatus() > -1)
c->SetStatus(-1);
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
return false; return false;
}else if (BytesRcv < 0) { } else if (BytesRcv < 0) {
if(c->GetStatus() > -1)c->SetStatus(-1); if (c->GetStatus() > -1)
c->SetStatus(-1);
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
return false; return false;
} }
if(strcmp(buf,"Done") == 0)return false; if (strcmp(buf, "Done") == 0)
std::string Ret(buf,BytesRcv); return false;
Parse(c,Ret); std::string Ret(buf, size_t(BytesRcv));
Parse(c, Ret);
return true; return true;
} }
void SyncResources(Client*c){ void SyncResources(Client* c) {
if(c == nullptr)return; Assert(c);
try{ if (c == nullptr)
STCPSend(c,Sec("WS")); return;
while(c->GetStatus() > -1 && STCPRecv(c)); try {
}catch (std::exception& e){ STCPSend(c, Sec("WS"));
while (c->GetStatus() > -1 && STCPRecv(c))
;
} catch (std::exception& e) {
except(Sec("Exception! : ") + std::string(e.what())); except(Sec("Exception! : ") + std::string(e.what()));
c->SetStatus(-1); c->SetStatus(-1);
} }

View File

@ -4,12 +4,21 @@
#include "Security/Enc.h" #include "Security/Enc.h"
#include "Network.h" #include "Network.h"
#include "Logger.h" #include "Logger.h"
#include "UnixCompat.h"
#include <thread> #include <thread>
void TCPSend(Client*c,const std::string&Data){ void TCPSend(Client*c,const std::string&Data){
Assert(c);
if(c == nullptr)return; if(c == nullptr)return;
std::string Send = "\n" + Data.substr(0,Data.find(char(0))) + "\n"; std::string Send = "\n" + Data.substr(0,Data.find(char(0))) + "\n";
size_t Sent = send(c->GetTCPSock(), Send.c_str(), int(Send.size()), 0); #ifdef WIN32
int Sent;
int len = static_cast<int>(Send.size());
#else
int64_t Sent;
size_t len = Send.size();
#endif // WIN32
Sent = send(c->GetTCPSock(), Send.c_str(), len, 0);
if (Sent == 0){ if (Sent == 0){
if(c->GetStatus() > -1)c->SetStatus(-1); if(c->GetStatus() > -1)c->SetStatus(-1);
}else if (Sent < 0) { }else if (Sent < 0) {
@ -18,41 +27,51 @@ void TCPSend(Client*c,const std::string&Data){
} }
} }
void TCPHandle(Client*c,const std::string& data){ void TCPHandle(Client*c,const std::string& data){
Assert(c);
#ifdef WIN32
__try{ __try{
#endif // WIN32
c->Handler.Handle(c,data); c->Handler.Handle(c,data);
#ifdef WIN32
}__except(1){ }__except(1){
c->Handler.clear(); c->Handler.clear();
} }
#endif // WIN32
} }
void TCPRcv(Client*c){ void TCPRcv(Client*c){
Assert(c);
if(c == nullptr || c->GetStatus() < 0)return; if(c == nullptr || c->GetStatus() < 0)return;
char buf[4096]; char buf[4096];
int len = 4096; size_t len = 4096;
ZeroMemory(buf, len); ZeroMemory(buf, len);
int BytesRcv = recv(c->GetTCPSock(), buf, len,0); int64_t BytesRcv = recv(c->GetTCPSock(), buf, len,0);
if (BytesRcv == 0){ if (BytesRcv == 0){
debug(Sec("(TCP) Connection closing...")); debug(Sec("(TCP) Connection closing..."));
if(c->GetStatus() > -1)c->SetStatus(-1); if(c->GetStatus() > -1)c->SetStatus(-1);
return; return;
}else if (BytesRcv < 0) { }else if (BytesRcv < 0) {
#ifdef WIN32
debug(Sec("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError())); debug(Sec("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
#else // unix
debug(Sec("(TCP) recv failed with error: ") + std::string(strerror(errno)));
#endif // WIN32
if(c->GetStatus() > -1)c->SetStatus(-1); if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock()); closesocket(c->GetTCPSock());
return; return;
} }
std::string Buf(buf,BytesRcv); std::string Buf(buf,(size_t(BytesRcv)));
TCPHandle(c,Buf); TCPHandle(c,Buf);
} }
void TCPClient(Client*c){ void TCPClient(Client*c){
DebugPrintTID();
Assert(c);
if(c->GetTCPSock() == -1){ if(c->GetTCPSock() == -1){
CI->RemoveClient(c); CI->RemoveClient(c);
return; return;
} }
OnConnect(c); OnConnect(c);
while (c->GetStatus() > -1)TCPRcv(c); while (c->GetStatus() > -1)TCPRcv(c);
__try{
OnDisconnect(c, c->GetStatus() == -2); OnDisconnect(c, c->GetStatus() == -2);
}__except(Handle(GetExceptionInformation(),Sec("OnDisconnect"))){}
} }
void InitClient(Client*c){ void InitClient(Client*c){
std::thread NewClient(TCPClient,c); std::thread NewClient(TCPClient,c);

View File

@ -2,137 +2,171 @@
/// Created by Anonymous275 on 5/8/2020 /// Created by Anonymous275 on 5/8/2020
/// ///
///UDP ///UDP
#include "Security/Enc.h"
#include "Compressor.h"
#include "Client.hpp" #include "Client.hpp"
#include "Settings.h" #include "Compressor.h"
#include "Network.h"
#include "Logger.h" #include "Logger.h"
#include <sstream> #include "Network.h"
#include <vector> #include "Security/Enc.h"
#include <thread> #include "Settings.h"
#include "UnixCompat.h"
#include <array> #include <array>
int FC(const std::string& s,const std::string& p,int n); #include <cmath>
struct PacketData{ #include <cstring>
#include <sstream>
#include <thread>
#include <vector>
int FC(const std::string& s, const std::string& p, int n);
struct PacketData {
int ID; int ID;
Client* Client; ::Client* Client;
std::string Data; std::string Data;
int Tries; int Tries;
}; };
struct SplitData{ struct SplitData {
int Total{}; int Total {};
int ID{}; int ID {};
std::set<std::pair<int,std::string>> Fragments; std::set<std::pair<int, std::string>> Fragments;
}; };
SOCKET UDPSock; SOCKET UDPSock;
std::set<PacketData*> DataAcks; std::set<PacketData*> DataAcks;
std::set<SplitData*> SplitPackets; std::set<SplitData*> SplitPackets;
void UDPSend(Client*c,std::string Data){ void UDPSend(Client* c, std::string Data) {
if(c == nullptr || !c->isConnected || c->GetStatus() < 0)return; Assert(c);
if (c == nullptr || !c->isConnected || c->GetStatus() < 0)
return;
sockaddr_in Addr = c->GetUDPAddr(); sockaddr_in Addr = c->GetUDPAddr();
int AddrSize = sizeof(c->GetUDPAddr()); socklen_t AddrSize = sizeof(c->GetUDPAddr());
Data = Data.substr(0,Data.find(char(0))); Data = Data.substr(0, Data.find(char(0)));
if(Data.length() > 400){ if (Data.length() > 400) {
std::string CMP(Comp(Data)); std::string CMP(Comp(Data));
Data = "ABG:" + CMP; Data = "ABG:" + CMP;
} }
int sendOk = sendto(UDPSock, Data.c_str(), int(Data.size()), 0, (sockaddr *) &Addr, AddrSize); #ifdef WIN32
if (sendOk == SOCKET_ERROR) { int sendOk;
int len = static_cast<int>(Data.size());
#else
int64_t sendOk;
size_t len = Data.size();
#endif // WIN32
sendOk = sendto(UDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, AddrSize);
#ifdef WIN32
if (sendOk != 0) {
debug(Sec("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError())); debug(Sec("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
if(c->GetStatus() > -1)c->SetStatus(-1); if (c->GetStatus() > -1)
c->SetStatus(-1);
} }
#else // unix
if (sendOk == -1) {
debug(Sec("(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"));
if (c->GetStatus() > -1)
c->SetStatus(-1);
}
#endif // WIN32
} }
void AckID(int ID){ void AckID(int ID) {
for(PacketData* p : DataAcks){ for (PacketData* p : DataAcks) {
if(p != nullptr && p->ID == ID){ if (p != nullptr && p->ID == ID) {
DataAcks.erase(p); DataAcks.erase(p);
break; break;
} }
} }
} }
int PacktID(){ int PacktID() {
static int ID = -1; static int ID = -1;
if(ID > 999999)ID = 0; if (ID > 999999)
else ID++; ID = 0;
else
ID++;
return ID; return ID;
} }
int SplitID(){ int SplitID() {
static int SID = -1; static int SID = -1;
if(SID > 999999)SID = 0; if (SID > 999999)
else SID++; SID = 0;
else
SID++;
return SID; return SID;
} }
void SendLarge(Client*c,std::string Data){ void SendLarge(Client* c, std::string Data) {
Data = Data.substr(0,Data.find(char(0))); Assert(c);
Data = Data.substr(0, Data.find(char(0)));
int ID = PacktID(); int ID = PacktID();
std::string Packet; std::string Packet;
if(Data.length() > 1000){ if (Data.length() > 1000) {
std::string pckt = Data; std::string pckt = Data;
int S = 1,Split = int(ceil(float(pckt.length()) / 1000)); int S = 1, Split = int(ceil(float(pckt.length()) / 1000));
int SID = SplitID(); int SID = SplitID();
while(pckt.length() > 1000){ while (pckt.length() > 1000) {
Packet = "SC|"+std::to_string(S)+"|"+std::to_string(Split)+"|"+std::to_string(ID)+"|"+ Packet = "SC|" + std::to_string(S) + "|" + std::to_string(Split) + "|" + std::to_string(ID) + "|" + std::to_string(SID) + "|" + pckt.substr(0, 1000);
std::to_string(SID)+"|"+pckt.substr(0,1000); DataAcks.insert(new PacketData { ID, c, Packet, 1 });
DataAcks.insert(new PacketData{ID,c,Packet,1}); UDPSend(c, Packet);
UDPSend(c,Packet);
pckt = pckt.substr(1000); pckt = pckt.substr(1000);
S++; S++;
ID = PacktID(); ID = PacktID();
} }
Packet = "SC|"+std::to_string(S)+"|"+std::to_string(Split)+"|"+ Packet = "SC|" + std::to_string(S) + "|" + std::to_string(Split) + "|" + std::to_string(ID) + "|" + std::to_string(SID) + "|" + pckt;
std::to_string(ID)+"|"+std::to_string(SID)+"|"+pckt; DataAcks.insert(new PacketData { ID, c, Packet, 1 });
DataAcks.insert(new PacketData{ID,c,Packet,1}); UDPSend(c, Packet);
UDPSend(c,Packet); } else {
}else{
Packet = "BD:" + std::to_string(ID) + ":" + Data; Packet = "BD:" + std::to_string(ID) + ":" + Data;
DataAcks.insert(new PacketData{ID,c,Packet,1}); DataAcks.insert(new PacketData { ID, c, Packet, 1 });
UDPSend(c,Packet); UDPSend(c, Packet);
} }
} }
struct HandledC{ struct HandledC {
int Pos = 0; size_t Pos = 0;
Client *c = nullptr; Client* c = nullptr;
std::array<int, 100> HandledIDs = {-1}; std::array<int, 100> HandledIDs = { -1 };
}; };
std::set<HandledC*> HandledIDs; std::set<HandledC*> HandledIDs;
void ResetIDs(HandledC*H){ void ResetIDs(HandledC* H) {
for(int C = 0;C < 100;C++){ for (size_t C = 0; C < 100; C++) {
H->HandledIDs.at(C) = -1; H->HandledIDs.at(C) = -1;
} }
} }
HandledC*GetHandled(Client*c){ HandledC* GetHandled(Client* c) {
for(HandledC*h : HandledIDs){ Assert(c);
if(h->c == c){ for (HandledC* h : HandledIDs) {
if (h->c == c) {
return h; return h;
} }
} }
return new HandledC(); return new HandledC();
} }
bool Handled(Client*c,int ID){ bool Handled(Client* c, int ID) {
Assert(c);
bool handle = false; bool handle = false;
for(HandledC*h : HandledIDs){ for (HandledC* h : HandledIDs) {
if(h->c == c){ if (h->c == c) {
for(int id : h->HandledIDs){ for (int id : h->HandledIDs) {
if(id == ID)return true; if (id == ID)
return true;
} }
if(h->Pos > 99)h->Pos = 0; if (h->Pos > 99)
h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID; h->HandledIDs.at(h->Pos) = ID;
h->Pos++; h->Pos++;
handle = true; handle = true;
} }
} }
for(HandledC*h : HandledIDs){ for (HandledC* h : HandledIDs) {
if(h->c == nullptr || !h->c->isConnected){ if (h->c == nullptr || !h->c->isConnected) {
HandledIDs.erase(h); HandledIDs.erase(h);
break; break;
} }
} }
if(!handle){ if (!handle) {
HandledC *h = GetHandled(c); HandledC* h = GetHandled(c);
ResetIDs(h); ResetIDs(h);
if (h->Pos > 99)h->Pos = 0; if (h->Pos > 99)
h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID; h->HandledIDs.at(h->Pos) = ID;
h->Pos++; h->Pos++;
h->c = c; h->c = c;
@ -140,89 +174,99 @@ bool Handled(Client*c,int ID){
} }
return false; return false;
} }
std::string UDPRcvFromClient(sockaddr_in& client){ std::string UDPRcvFromClient(sockaddr_in& client) {
int clientLength = sizeof(client); size_t clientLength = sizeof(client);
ZeroMemory(&client, clientLength); ZeroMemory(&client, clientLength);
std::string Ret(10240,0); std::string Ret(10240, 0);
int Rcv = recvfrom(UDPSock, &Ret[0], 10240, 0, (sockaddr*)&client, &clientLength); int64_t Rcv = recvfrom(UDPSock, &Ret[0], 10240, 0, (sockaddr*)&client, (socklen_t*)&clientLength);
if (Rcv == -1){ if (Rcv == -1) {
#ifdef WIN32
error(Sec("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError())); error(Sec("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
#else // unix
error(Sec("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno)));
#endif // WIN32
return ""; return "";
} }
return Ret; return Ret;
} }
SplitData*GetSplit(int SplitID){ SplitData* GetSplit(int SplitID) {
for(SplitData* a : SplitPackets){ for (SplitData* a : SplitPackets) {
if(a->ID == SplitID)return a; if (a->ID == SplitID)
return a;
} }
auto* SP = new SplitData(); auto* SP = new SplitData();
SplitPackets.insert(SP); SplitPackets.insert(SP);
return SP; return SP;
} }
void HandleChunk(Client*c,const std::string&Data){ void HandleChunk(Client* c, const std::string& Data) {
int pos = FC(Data,"|",5); Assert(c);
if(pos == -1)return; int pos = FC(Data, "|", 5);
std::stringstream ss(Data.substr(0,pos++)); if (pos == -1)
return;
std::stringstream ss(Data.substr(0, size_t(pos++)));
std::string t; std::string t;
int I = -1; int I = -1;
//Current Max ID SID //Current Max ID SID
std::vector<int> Num(4,0); std::vector<int> Num(4, 0);
while (std::getline(ss, t, '|')) { while (std::getline(ss, t, '|')) {
if(I != -1)Num.at(I) = std::stoi(t); if (I >= 0)
Num.at(size_t(I)) = std::stoi(t);
I++; I++;
} }
std::string ack = "TRG:" + std::to_string(Num.at(2)); std::string ack = "TRG:" + std::to_string(Num.at(2));
UDPSend(c,ack); UDPSend(c, ack);
if(Handled(c,Num.at(2))){ if (Handled(c, Num.at(2))) {
return; return;
} }
std::string Packet = Data.substr(pos); std::string Packet = Data.substr(size_t(pos));
SplitData* SData = GetSplit(Num.at(3)); SplitData* SData = GetSplit(Num.at(3));
SData->Total = Num.at(1); SData->Total = Num.at(1);
SData->ID = Num.at(3); SData->ID = Num.at(3);
SData->Fragments.insert(std::make_pair(Num.at(0),Packet)); SData->Fragments.insert(std::make_pair(Num.at(0), Packet));
if(SData->Fragments.size() == SData->Total){ if (SData->Fragments.size() == size_t(SData->Total)) {
std::string ToHandle; std::string ToHandle;
for(const std::pair<int,std::string>& a : SData->Fragments){ for (const std::pair<int, std::string>& a : SData->Fragments) {
ToHandle += a.second; ToHandle += a.second;
} }
GParser(c,ToHandle); GParser(c, ToHandle);
SplitPackets.erase(SData); SplitPackets.erase(SData);
delete SData; delete SData;
SData = nullptr; SData = nullptr;
} }
} }
void UDPParser(Client*c,std::string Packet){ void UDPParser(Client* c, std::string Packet) {
if(Packet.substr(0,4) == "ABG:"){ Assert(c);
if (Packet.substr(0, 4) == "ABG:") {
Packet = DeComp(Packet.substr(4)); Packet = DeComp(Packet.substr(4));
} }
if(Packet.substr(0,4) == "TRG:"){ if (Packet.substr(0, 4) == "TRG:") {
std::string pkt = Packet.substr(4); std::string pkt = Packet.substr(4);
if(Packet.find_first_not_of("0123456789") == -1){ if (Packet.find_first_not_of("0123456789") == std::string::npos) {
AckID(stoi(Packet)); AckID(stoi(Packet));
} }
return; return;
}else if(Packet.substr(0,3) == "BD:"){ } else if (Packet.substr(0, 3) == "BD:") {
auto pos = Packet.find(':',4); auto pos = Packet.find(':', 4);
int ID = stoi(Packet.substr(3,pos-3)); int ID = stoi(Packet.substr(3, pos - 3));
std::string pkt = "TRG:" + std::to_string(ID); std::string pkt = "TRG:" + std::to_string(ID);
UDPSend(c,pkt); UDPSend(c, pkt);
if(!Handled(c,ID)) { if (!Handled(c, ID)) {
pkt = Packet.substr(pos + 1); pkt = Packet.substr(pos + 1);
GParser(c, pkt); GParser(c, pkt);
} }
return; return;
}else if(Packet.substr(0,2) == "SC"){ } else if (Packet.substr(0, 2) == "SC") {
HandleChunk(c,Packet); HandleChunk(c, Packet);
return; return;
} }
GParser(c,Packet); GParser(c, Packet);
} }
void LOOP(){ void LOOP() {
while(UDPSock != -1) { DebugPrintTID();
for (PacketData* p : DataAcks){ while (UDPSock != -1) {
if(p != nullptr) { for (PacketData* p : DataAcks) {
if (p != nullptr) {
if (p->Client == nullptr || p->Client->GetTCPSock() == -1) { if (p->Client == nullptr || p->Client->GetTCPSock() == -1) {
DataAcks.erase(p); DataAcks.erase(p);
break; break;
@ -239,22 +283,23 @@ void LOOP(){
std::this_thread::sleep_for(std::chrono::milliseconds(300)); std::this_thread::sleep_for(std::chrono::milliseconds(300));
} }
} }
[[noreturn]] void UDPServerMain(){ [[noreturn]] void UDPServerMain() {
#ifdef WIN32
WSADATA data; WSADATA data;
if (WSAStartup(514, &data)){ if (WSAStartup(514, &data)) {
error(Sec("Can't start Winsock!")); error(Sec("Can't start Winsock!"));
//return; //return;
} }
UDPSock = socket(AF_INET, SOCK_DGRAM, 0); UDPSock = socket(AF_INET, SOCK_DGRAM, 0);
// Create a server hint structure for the server // Create a server hint structure for the server
sockaddr_in serverAddr{}; sockaddr_in serverAddr {};
serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local
serverAddr.sin_family = AF_INET; // Address format is IPv4 serverAddr.sin_family = AF_INET; // Address format is IPv4
serverAddr.sin_port = htons(Port); // Convert from little to big endian serverAddr.sin_port = htons(Port); // Convert from little to big endian
// Try and bind the socket to the IP and port // Try and bind the socket to the IP and port
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){ if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
error(Sec("Can't bind socket!") + std::to_string(WSAGetLastError())); error(Sec("Can't bind socket!") + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5)); std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1); exit(-1);
@ -265,25 +310,69 @@ void LOOP(){
std::thread Ack(LOOP); std::thread Ack(LOOP);
Ack.detach(); 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(Sec("Vehicle data network online on port ") + std::to_string(Port) + Sec(" with a Max of ") + std::to_string(MaxPlayers) + Sec(" Clients"));
while (true){ while (true) {
sockaddr_in client{}; sockaddr_in client {};
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
auto Pos = Data.find(':'); auto Pos = Data.find(':');
if(Data.empty() || Pos < 0 || Pos > 2)continue; if (Data.empty() || Pos < 0 || Pos > 2)
continue;
/*char clientIp[256]; /*char clientIp[256];
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/ inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
uint8_t ID = Data.at(0)-1; uint8_t ID = Data.at(0) - 1;
for(Client*c : CI->Clients){ for (Client* c : CI->Clients) {
if(c != nullptr && c->GetID() == ID){ if (c != nullptr && c->GetID() == ID) {
c->SetUDPAddr(client); c->SetUDPAddr(client);
c->isConnected = true; c->isConnected = true;
UDPParser(c,Data.substr(2)); UDPParser(c, Data.substr(2));
} }
} }
} }
/*closesocket(UDPSock); /*closesocket(UDPSock);
WSACleanup(); WSACleanup();
return;*/ return;*/
#else // unix
UDPSock = socket(AF_INET, SOCK_DGRAM, 0);
// Create a server hint structure for the server
sockaddr_in serverAddr {};
serverAddr.sin_addr.s_addr = INADDR_ANY; //Any Local
serverAddr.sin_family = AF_INET; // Address format is IPv4
serverAddr.sin_port = htons(uint16_t(Port)); // Convert from little to big endian
// 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)));
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"));
while (true) {
sockaddr_in client {};
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
size_t Pos = Data.find(':');
if (Data.empty() || Pos > 2)
continue;
/*char clientIp[256];
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
uint8_t ID = uint8_t(Data.at(0)) - 1;
for (Client* c : CI->Clients) {
if (c != nullptr && c->GetID() == ID) {
c->SetUDPAddr(client);
c->isConnected = true;
UDPParser(c, Data.substr(2));
}
}
}
/*closesocket(UDPSock); // TODO: Why not this? We did this in TCPServerMain?
return;
*/
#endif // WIN32
} }

View File

@ -1,25 +1,45 @@
/// ///
/// Created by Anonymous275 on 7/17/2020 /// Created by Anonymous275 on 7/17/2020
/// ///
#include "Logger.h"
#include "Security/Enc.h" #include "Security/Enc.h"
#include "Settings.h" #include "Settings.h"
#include "Logger.h"
#include <fstream>
#include <sstream>
#include <chrono> #include <chrono>
#include <fstream>
#include <mutex> #include <mutex>
#include <sstream>
#include <thread>
void DebugPrintTIDInternal(const std::string& func) {
// we need to print to cout here as we might crash before all console output is handled,
// due to segfaults or asserts.
#ifdef DEBUG
MLock.lock();
printf("%c[2K\r", 27);
std::cout << "(debug build) Thread '" << std::this_thread::get_id() << "' is " << func << std::endl;
MLock.unlock();
#endif // DEBUG
}
std::string getDate() { std::string getDate() {
typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>::type> days; 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::time_point now = std::chrono::system_clock::now();
std::chrono::system_clock::duration tp = now.time_since_epoch(); std::chrono::system_clock::duration tp = now.time_since_epoch();
days d = std::chrono::duration_cast<days>(tp);tp -= d; days d = std::chrono::duration_cast<days>(tp);
auto h = std::chrono::duration_cast<std::chrono::hours>(tp);tp -= h; tp -= d;
auto m = std::chrono::duration_cast<std::chrono::minutes>(tp);tp -= m; auto h = std::chrono::duration_cast<std::chrono::hours>(tp);
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp);tp -= s; 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); time_t tt = std::chrono::system_clock::to_time_t(now);
tm local_tm{}; tm local_tm {};
localtime_s(&local_tm,&tt); #ifdef WIN32
localtime_s(&local_tm, &tt);
#else // unix
localtime_r(&tt, &local_tm);
#endif // WIN32
std::stringstream date; std::stringstream date;
int S = local_tm.tm_sec; int S = local_tm.tm_sec;
int M = local_tm.tm_min; int M = local_tm.tm_min;
@ -38,17 +58,18 @@ std::string getDate() {
<< "] "; << "] ";
return date.str(); return date.str();
} }
void InitLog(){ void InitLog() {
std::ofstream LFS; std::ofstream LFS;
LFS.open (Sec("Server.log")); LFS.open(Sec("Server.log"));
if(!LFS.is_open()){ if (!LFS.is_open()) {
error(Sec("logger file init failed!")); error(Sec("logger file init failed!"));
}else LFS.close(); } else
LFS.close();
} }
std::mutex LogLock; std::mutex LogLock;
void addToLog(const std::string& Line){ void addToLog(const std::string& Line) {
std::ofstream LFS; std::ofstream LFS;
LFS.open (Sec("Server.log"), std::ios_base::app); LFS.open(Sec("Server.log"), std::ios_base::app);
LFS << Line.c_str(); LFS << Line.c_str();
LFS.close(); LFS.close();
} }
@ -60,14 +81,15 @@ void info(const std::string& toPrint) {
LogLock.unlock(); LogLock.unlock();
} }
void debug(const std::string& toPrint) { void debug(const std::string& toPrint) {
if(!Debug)return; if (!Debug)
return;
LogLock.lock(); LogLock.lock();
std::string Print = getDate() + Sec("[DEBUG] ") + toPrint + "\n"; std::string Print = getDate() + Sec("[DEBUG] ") + toPrint + "\n";
ConsoleOut(Print); ConsoleOut(Print);
addToLog(Print); addToLog(Print);
LogLock.unlock(); LogLock.unlock();
} }
void warn(const std::string& toPrint){ void warn(const std::string& toPrint) {
LogLock.lock(); LogLock.lock();
std::string Print = getDate() + Sec("[WARN] ") + toPrint + "\n"; std::string Print = getDate() + Sec("[WARN] ") + toPrint + "\n";
ConsoleOut(Print); ConsoleOut(Print);
@ -80,7 +102,8 @@ void error(const std::string& toPrint) {
std::string Print = getDate() + Sec("[ERROR] ") + toPrint + "\n"; std::string Print = getDate() + Sec("[ERROR] ") + toPrint + "\n";
ConsoleOut(Print); ConsoleOut(Print);
addToLog(Print); addToLog(Print);
if(ECounter > 10)exit(7); if (ECounter > 10)
exit(7);
ECounter++; ECounter++;
LogLock.unlock(); LogLock.unlock();
} }

View File

@ -1,13 +1,19 @@
#include "Startup.h" #include "Startup.h"
#include "CustomAssert.h"
#include "Curl/curl.h"
#include <thread> #include <thread>
#include <iostream> #include <iostream>
[[noreturn]] void loop(){ [[noreturn]] void loop(){
DebugPrintTID();
while(true){ while(true){
std::cout.flush(); std::cout.flush();
std::this_thread::sleep_for(std::chrono::milliseconds(600)); std::this_thread::sleep_for(std::chrono::milliseconds(600));
} }
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
DebugPrintTID();
// curl needs to be initialized to properly deallocate its resources later
Assert(curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK);
#ifdef DEBUG #ifdef DEBUG
std::thread t1(loop); std::thread t1(loop);
t1.detach(); t1.detach();
@ -20,5 +26,7 @@ int main(int argc, char* argv[]) {
HBInit(); HBInit();
StatInit(); StatInit();
NetMain(); NetMain();
// clean up curl at the end to be sure
curl_global_cleanup();
return 0; return 0;
} }