Skip to content

Commit 5ebf81a

Browse files
authored
Merge pull request #3 from kriegalex/develop
Merge develop
2 parents 78fbe64 + 74a1eee commit 5ebf81a

20 files changed

+25826
-2
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,12 @@
3030
*.exe
3131
*.out
3232
*.app
33+
34+
# certificates
35+
*.pem
36+
37+
# Bin
38+
bin/
39+
40+
# cmake folders
41+
cmake-*/

CMakeLists.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
project(SecureSyslogServer)
3+
4+
# Set the C++ standard for the project
5+
set(CMAKE_CXX_STANDARD 17)
6+
7+
set(OPENSSL_ROOT_DIR ON CACHE BOOL "OpenSSL root directory")
8+
9+
find_package(OpenSSL REQUIRED)
10+
if (OPENSSL_FOUND)
11+
message(STATUS "OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
12+
message(STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")
13+
endif ()
14+
15+
# Create an executable with this project's source files
16+
add_executable(${PROJECT_NAME} main.cpp
17+
SyslogServer.cpp
18+
Config.cpp
19+
SSLUtil.cpp
20+
Logger.cpp
21+
MemoryBoundedQueue.cpp)
22+
target_link_libraries(SecureSyslogServer OpenSSL::SSL OpenSSL::Crypto)
23+
if (WIN32)
24+
target_link_libraries(${PROJECT_NAME} ws2_32)
25+
endif ()
26+
target_include_directories(SecureSyslogServer PRIVATE ${OPENSSL_INCLUDE_DIR})
27+
28+
# Set the output directory for runtime binary (executables)
29+
set_target_properties(${PROJECT_NAME} PROPERTIES
30+
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin
31+
)
32+
33+
# Copy a specific file
34+
file(COPY ${PROJECT_SOURCE_DIR}/res/server.pem DESTINATION ${PROJECT_SOURCE_DIR}/bin/Debug)
35+
file(COPY ${PROJECT_SOURCE_DIR}/res/server.pem DESTINATION ${PROJECT_SOURCE_DIR}/bin/Release)
36+
file(COPY ${PROJECT_SOURCE_DIR}/res/config.json DESTINATION ${PROJECT_SOURCE_DIR}/bin/Debug)
37+
file(COPY ${PROJECT_SOURCE_DIR}/res/config.json DESTINATION ${PROJECT_SOURCE_DIR}/bin/Release)

Config.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "Config.h"
2+
#include <fstream>
3+
#include "json.hpp"
4+
5+
using json = nlohmann::json;
6+
7+
Config::Config(const std::string &configPath) {
8+
loadConfig(configPath);
9+
}
10+
11+
void Config::loadConfig(const std::string &path) {
12+
std::ifstream configFile(path);
13+
json configJson;
14+
configFile >> configJson;
15+
16+
server_port_ = configJson["server_port"];
17+
output_to_screen_ = configJson["screen_output"];
18+
syslog_file_max_size_kb_ = configJson["file_max_size_kb"];
19+
syslog_max_memory_size_kb_ = configJson["max_memory_size_kb"];
20+
auto colors = configJson["priority_colors"];
21+
for (const auto &elt : levels) {
22+
// set default then check config.json
23+
priorityColors[elt] = defaultColors.at(elt);
24+
// info, debug, ... exist as keys in the config.json
25+
if (colors.find(elt) != colors.end()) {
26+
// the given color strings in config.json exist in our mapping table
27+
if (winTerminalColors.find(colors[elt]) != winTerminalColors.end()) {
28+
priorityColors[elt] = winTerminalColors.at(colors[elt]);
29+
}
30+
}
31+
}
32+
}
33+
34+
unsigned long Config::getMaxMemorySizeKb() const {
35+
return syslog_max_memory_size_kb_;
36+
}
37+
38+
int Config::getServerPort() const {
39+
return server_port_;
40+
}
41+
42+
int Config::getErrorSeverityColorCode() const {
43+
return priorityColors.at("error");
44+
}
45+
46+
int Config::getInfoSeverityColorCode() const {
47+
return priorityColors.at("info");
48+
}
49+
50+
int Config::getDebugSeverityColorCode() const {
51+
return priorityColors.at("debug");
52+
}
53+
54+
unsigned long Config::getFileMaxSizeKb() const {
55+
return syslog_file_max_size_kb_;
56+
}
57+
58+
bool Config::isOutputToScreen() const {
59+
return output_to_screen_;
60+
}

Config.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef SYSLOGCONFIG_H
2+
#define SYSLOGCONFIG_H
3+
4+
#include <unordered_map>
5+
#include <string>
6+
#include <array>
7+
8+
class Config {
9+
public:
10+
explicit Config(const std::string &configPath);
11+
int getServerPort() const;
12+
int getErrorSeverityColorCode() const;
13+
int getInfoSeverityColorCode() const;
14+
int getDebugSeverityColorCode() const;
15+
unsigned long getFileMaxSizeKb() const;
16+
bool isOutputToScreen() const;
17+
unsigned long getMaxMemorySizeKb() const;
18+
19+
private:
20+
int server_port_ = 60119;
21+
bool output_to_screen_ = false;
22+
unsigned long syslog_file_max_size_kb_ = 1000; // 1MB
23+
unsigned long syslog_max_memory_size_kb_ = 1000000; // 1GB
24+
std::unordered_map<std::string, int> priorityColors;
25+
void loadConfig(const std::string &path);
26+
const std::array<std::string, 3> levels = {"error", "info", "debug"};
27+
const std::unordered_map<std::string, int> defaultColors = {{"error", 12}, {"info", 1}, {"debug", 8}};
28+
const std::unordered_map<std::string, int> winTerminalColors = {
29+
{"BLACK", 0},
30+
{"BLUE", 1},
31+
{"GREEN", 2},
32+
{"CYAN", 3},
33+
{"RED", 4},
34+
{"MAGENTA", 5},
35+
{"YELLOW", 6},
36+
{"WHITE", 7},
37+
{"BRIGHT_BLACK", 8},
38+
{"BRIGHT_BLUE", 9},
39+
{"BRIGHT_GREEN", 10},
40+
{"BRIGHT_CYAN", 11},
41+
{"BRIGHT_RED", 12},
42+
{"BRIGHT_MAGENTA", 13},
43+
{"BRIGHT_YELLOW", 14},
44+
{"BRIGHT_WHITE", 15}};
45+
};
46+
47+
#endif

FileLogger.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#pragma once
2+
3+
#include <fstream>
4+
#include <atomic>
5+
#include <thread>
6+
#include <mutex>
7+
#include <utility>
8+
#include <filesystem>
9+
#include <sstream>
10+
11+
#include "MemoryBoundedQueue.h"
12+
13+
class FileLogger {
14+
private:
15+
MemoryBoundedQueue<std::string> &queue_;
16+
std::ofstream file_stream_;
17+
std::atomic<bool> running_ = true;
18+
std::atomic<bool> wait_ = false;
19+
std::thread worker_;
20+
std::mutex mtx_;
21+
std::string filename_;
22+
const std::chrono::milliseconds flush_interval_ = std::chrono::milliseconds(100);
23+
const unsigned long max_file_size_;
24+
bool stopWorker = false;
25+
26+
// Generate a filename based on the current date and time
27+
static std::string getFormattedFilename() {
28+
// Get current time as system_clock time_point
29+
auto now = std::chrono::system_clock::now();
30+
// Convert to time_t for compatibility with C time functions
31+
auto now_c = std::chrono::system_clock::to_time_t(now);
32+
// Convert to tm struct for use with put_time
33+
struct tm now_tm{};
34+
localtime_s(&now_tm, &now_c);
35+
36+
// Use ostringstream to format filename
37+
std::ostringstream oss;
38+
oss << std::put_time(&now_tm, "syslog_%Y_%m_%d_%H_%M_%S.txt");
39+
40+
return oss.str();
41+
}
42+
43+
// Open a new log file with the current timestamp
44+
void openNewLogFile() {
45+
if (file_stream_.is_open()) {
46+
file_stream_.close();
47+
}
48+
filename_ = getFormattedFilename();
49+
file_stream_.open(filename_, std::ios::app);
50+
}
51+
52+
// Check the size of the current log file and rotate if necessary
53+
void checkAndRotateFile() {
54+
if (std::filesystem::file_size(filename_) >= max_file_size_) {
55+
openNewLogFile();
56+
}
57+
}
58+
59+
void backgroundScreenFlush() {
60+
while (!stopWorker) {
61+
std::this_thread::sleep_for(flush_interval_);
62+
std::lock_guard<std::mutex> lock(mtx_);
63+
file_stream_.flush();
64+
}
65+
}
66+
67+
public:
68+
FileLogger(MemoryBoundedQueue<std::string> &q, unsigned long file_size)
69+
: filename_(std::move(getFormattedFilename())),
70+
max_file_size_(file_size),
71+
queue_(q) {
72+
worker_ = std::thread(&::FileLogger::backgroundScreenFlush, this);
73+
}
74+
75+
~FileLogger() {
76+
stopWorker = true;
77+
worker_.join();
78+
if (file_stream_.is_open()) {
79+
file_stream_.close();
80+
}
81+
}
82+
83+
void run() {
84+
file_stream_.open(filename_, std::ios::app);
85+
unsigned int count = 0;
86+
while (running_) {
87+
std::string log = queue_.pop();
88+
std::lock_guard<std::mutex> lock(mtx_);
89+
file_stream_ << log << std::endl;
90+
checkAndRotateFile();
91+
}
92+
file_stream_.flush(); // in case wait_ is used and takes time
93+
if (wait_) {
94+
while (!queue_.empty()) {
95+
std::string log = queue_.pop();
96+
std::lock_guard<std::mutex> lock(mtx_);
97+
file_stream_ << log << std::endl;
98+
checkAndRotateFile();
99+
}
100+
file_stream_.flush();
101+
}
102+
}
103+
104+
void stop() {
105+
wait_ = false;
106+
running_ = false;
107+
}
108+
109+
void stopWaitFinished() {
110+
wait_ = true;
111+
running_ = false;
112+
}
113+
};

0 commit comments

Comments
 (0)