Skip to content

Commit

Permalink
Merge pull request #3 from kriegalex/develop
Browse files Browse the repository at this point in the history
Merge develop
  • Loading branch information
kriegalex authored Apr 30, 2024
2 parents 78fbe64 + 74a1eee commit 5ebf81a
Show file tree
Hide file tree
Showing 20 changed files with 25,826 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@
*.exe
*.out
*.app

# certificates
*.pem

# Bin
bin/

# cmake folders
cmake-*/
37 changes: 37 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.15)
project(SecureSyslogServer)

# Set the C++ standard for the project
set(CMAKE_CXX_STANDARD 17)

set(OPENSSL_ROOT_DIR ON CACHE BOOL "OpenSSL root directory")

find_package(OpenSSL REQUIRED)
if (OPENSSL_FOUND)
message(STATUS "OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
message(STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")
endif ()

# Create an executable with this project's source files
add_executable(${PROJECT_NAME} main.cpp
SyslogServer.cpp
Config.cpp
SSLUtil.cpp
Logger.cpp
MemoryBoundedQueue.cpp)
target_link_libraries(SecureSyslogServer OpenSSL::SSL OpenSSL::Crypto)
if (WIN32)
target_link_libraries(${PROJECT_NAME} ws2_32)
endif ()
target_include_directories(SecureSyslogServer PRIVATE ${OPENSSL_INCLUDE_DIR})

# Set the output directory for runtime binary (executables)
set_target_properties(${PROJECT_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin
)

# Copy a specific file
file(COPY ${PROJECT_SOURCE_DIR}/res/server.pem DESTINATION ${PROJECT_SOURCE_DIR}/bin/Debug)
file(COPY ${PROJECT_SOURCE_DIR}/res/server.pem DESTINATION ${PROJECT_SOURCE_DIR}/bin/Release)
file(COPY ${PROJECT_SOURCE_DIR}/res/config.json DESTINATION ${PROJECT_SOURCE_DIR}/bin/Debug)
file(COPY ${PROJECT_SOURCE_DIR}/res/config.json DESTINATION ${PROJECT_SOURCE_DIR}/bin/Release)
60 changes: 60 additions & 0 deletions Config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "Config.h"
#include <fstream>
#include "json.hpp"

using json = nlohmann::json;

Config::Config(const std::string &configPath) {
loadConfig(configPath);
}

void Config::loadConfig(const std::string &path) {
std::ifstream configFile(path);
json configJson;
configFile >> configJson;

server_port_ = configJson["server_port"];
output_to_screen_ = configJson["screen_output"];
syslog_file_max_size_kb_ = configJson["file_max_size_kb"];
syslog_max_memory_size_kb_ = configJson["max_memory_size_kb"];
auto colors = configJson["priority_colors"];
for (const auto &elt : levels) {
// set default then check config.json
priorityColors[elt] = defaultColors.at(elt);
// info, debug, ... exist as keys in the config.json
if (colors.find(elt) != colors.end()) {
// the given color strings in config.json exist in our mapping table
if (winTerminalColors.find(colors[elt]) != winTerminalColors.end()) {
priorityColors[elt] = winTerminalColors.at(colors[elt]);
}
}
}
}

unsigned long Config::getMaxMemorySizeKb() const {
return syslog_max_memory_size_kb_;
}

int Config::getServerPort() const {
return server_port_;
}

int Config::getErrorSeverityColorCode() const {
return priorityColors.at("error");
}

int Config::getInfoSeverityColorCode() const {
return priorityColors.at("info");
}

int Config::getDebugSeverityColorCode() const {
return priorityColors.at("debug");
}

unsigned long Config::getFileMaxSizeKb() const {
return syslog_file_max_size_kb_;
}

bool Config::isOutputToScreen() const {
return output_to_screen_;
}
47 changes: 47 additions & 0 deletions Config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef SYSLOGCONFIG_H
#define SYSLOGCONFIG_H

#include <unordered_map>
#include <string>
#include <array>

class Config {
public:
explicit Config(const std::string &configPath);
int getServerPort() const;
int getErrorSeverityColorCode() const;
int getInfoSeverityColorCode() const;
int getDebugSeverityColorCode() const;
unsigned long getFileMaxSizeKb() const;
bool isOutputToScreen() const;
unsigned long getMaxMemorySizeKb() const;

private:
int server_port_ = 60119;
bool output_to_screen_ = false;
unsigned long syslog_file_max_size_kb_ = 1000; // 1MB
unsigned long syslog_max_memory_size_kb_ = 1000000; // 1GB
std::unordered_map<std::string, int> priorityColors;
void loadConfig(const std::string &path);
const std::array<std::string, 3> levels = {"error", "info", "debug"};
const std::unordered_map<std::string, int> defaultColors = {{"error", 12}, {"info", 1}, {"debug", 8}};
const std::unordered_map<std::string, int> winTerminalColors = {
{"BLACK", 0},
{"BLUE", 1},
{"GREEN", 2},
{"CYAN", 3},
{"RED", 4},
{"MAGENTA", 5},
{"YELLOW", 6},
{"WHITE", 7},
{"BRIGHT_BLACK", 8},
{"BRIGHT_BLUE", 9},
{"BRIGHT_GREEN", 10},
{"BRIGHT_CYAN", 11},
{"BRIGHT_RED", 12},
{"BRIGHT_MAGENTA", 13},
{"BRIGHT_YELLOW", 14},
{"BRIGHT_WHITE", 15}};
};

#endif
113 changes: 113 additions & 0 deletions FileLogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#pragma once

#include <fstream>
#include <atomic>
#include <thread>
#include <mutex>
#include <utility>
#include <filesystem>
#include <sstream>

#include "MemoryBoundedQueue.h"

class FileLogger {
private:
MemoryBoundedQueue<std::string> &queue_;
std::ofstream file_stream_;
std::atomic<bool> running_ = true;
std::atomic<bool> wait_ = false;
std::thread worker_;
std::mutex mtx_;
std::string filename_;
const std::chrono::milliseconds flush_interval_ = std::chrono::milliseconds(100);
const unsigned long max_file_size_;
bool stopWorker = false;

// Generate a filename based on the current date and time
static std::string getFormattedFilename() {
// Get current time as system_clock time_point
auto now = std::chrono::system_clock::now();
// Convert to time_t for compatibility with C time functions
auto now_c = std::chrono::system_clock::to_time_t(now);
// Convert to tm struct for use with put_time
struct tm now_tm{};
localtime_s(&now_tm, &now_c);

// Use ostringstream to format filename
std::ostringstream oss;
oss << std::put_time(&now_tm, "syslog_%Y_%m_%d_%H_%M_%S.txt");

return oss.str();
}

// Open a new log file with the current timestamp
void openNewLogFile() {
if (file_stream_.is_open()) {
file_stream_.close();
}
filename_ = getFormattedFilename();
file_stream_.open(filename_, std::ios::app);
}

// Check the size of the current log file and rotate if necessary
void checkAndRotateFile() {
if (std::filesystem::file_size(filename_) >= max_file_size_) {
openNewLogFile();
}
}

void backgroundScreenFlush() {
while (!stopWorker) {
std::this_thread::sleep_for(flush_interval_);
std::lock_guard<std::mutex> lock(mtx_);
file_stream_.flush();
}
}

public:
FileLogger(MemoryBoundedQueue<std::string> &q, unsigned long file_size)
: filename_(std::move(getFormattedFilename())),
max_file_size_(file_size),
queue_(q) {
worker_ = std::thread(&::FileLogger::backgroundScreenFlush, this);
}

~FileLogger() {
stopWorker = true;
worker_.join();
if (file_stream_.is_open()) {
file_stream_.close();
}
}

void run() {
file_stream_.open(filename_, std::ios::app);
unsigned int count = 0;
while (running_) {
std::string log = queue_.pop();
std::lock_guard<std::mutex> lock(mtx_);
file_stream_ << log << std::endl;
checkAndRotateFile();
}
file_stream_.flush(); // in case wait_ is used and takes time
if (wait_) {
while (!queue_.empty()) {
std::string log = queue_.pop();
std::lock_guard<std::mutex> lock(mtx_);
file_stream_ << log << std::endl;
checkAndRotateFile();
}
file_stream_.flush();
}
}

void stop() {
wait_ = false;
running_ = false;
}

void stopWaitFinished() {
wait_ = true;
running_ = false;
}
};
Loading

0 comments on commit 5ebf81a

Please sign in to comment.