232 lines
7.1 KiB
C++
232 lines
7.1 KiB
C++
#pragma once
|
|
|
|
#include "tl/expected.hpp"
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cctype>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <memory_resource>
|
|
#include <sstream>
|
|
#include <string_view>
|
|
|
|
#include <alloca.h>
|
|
#include <cassert>
|
|
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_modules.h>
|
|
#include <syslog.h>
|
|
#include <unistd.h>
|
|
#include <utility>
|
|
|
|
namespace rublon {
|
|
namespace memory {
|
|
struct holder {
|
|
static inline std::pmr::memory_resource * _mr = std::pmr::get_default_resource();
|
|
};
|
|
|
|
inline void set_default_resource(std::pmr::memory_resource * memory_resource) {
|
|
holder{}._mr = memory_resource;
|
|
}
|
|
|
|
inline std::pmr::memory_resource * default_resource() {
|
|
return holder{}._mr;
|
|
}
|
|
|
|
template < std::size_t N >
|
|
class MonotonicStackResource : public std::pmr::monotonic_buffer_resource {
|
|
char _buffer[N];
|
|
|
|
public:
|
|
MonotonicStackResource() : std::pmr::monotonic_buffer_resource{_buffer, N, std::pmr::null_memory_resource()} {}
|
|
};
|
|
|
|
template < std::size_t N >
|
|
class UnsynchronizedStackResource : public std::pmr::unsynchronized_pool_resource {
|
|
MonotonicStackResource< N > _upstream;
|
|
|
|
public:
|
|
UnsynchronizedStackResource() : std::pmr::unsynchronized_pool_resource{&_upstream} {}
|
|
};
|
|
|
|
class MonotonicHeapResourceBase {
|
|
public:
|
|
std::pmr::memory_resource * _upstream{};
|
|
std::size_t _size{};
|
|
void * _buffer{nullptr};
|
|
|
|
MonotonicHeapResourceBase(std::size_t size) : _upstream{default_resource()}, _size{size}, _buffer{_upstream->allocate(size)} {}
|
|
|
|
~MonotonicHeapResourceBase() {
|
|
if(_buffer)
|
|
_upstream->deallocate(_buffer, _size);
|
|
}
|
|
};
|
|
|
|
template < std::size_t N >
|
|
class MonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource {
|
|
public:
|
|
MonotonicHeapResource()
|
|
: MonotonicHeapResourceBase{N}, std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, default_resource()} {}
|
|
};
|
|
|
|
template < std::size_t N >
|
|
class StrictMonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource {
|
|
public:
|
|
StrictMonotonicHeapResource()
|
|
: MonotonicHeapResourceBase{N},
|
|
std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, std::pmr::null_memory_resource()} {}
|
|
};
|
|
|
|
using StrictMonotonic_1k_HeapResource = StrictMonotonicHeapResource< 1 * 1024 >;
|
|
using StrictMonotonic_2k_HeapResource = StrictMonotonicHeapResource< 2 * 1024 >;
|
|
using StrictMonotonic_4k_HeapResource = StrictMonotonicHeapResource< 4 * 1024 >;
|
|
using StrictMonotonic_8k_HeapResource = StrictMonotonicHeapResource< 8 * 1024 >;
|
|
|
|
using Monotonic_1k_HeapResource = MonotonicHeapResource< 1 * 1024 >;
|
|
using Monotonic_2k_HeapResource = MonotonicHeapResource< 2 * 1024 >;
|
|
using Monotonic_4k_HeapResource = MonotonicHeapResource< 4 * 1024 >;
|
|
using Monotonic_8k_HeapResource = MonotonicHeapResource< 8 * 1024 >;
|
|
} // namespace memory
|
|
|
|
enum class LogLevel { Debug, Info, Warning, Error };
|
|
|
|
inline auto dateStr() {
|
|
std::array< char, 32 > date;
|
|
time_t now;
|
|
time(&now);
|
|
strftime(date.data(), date.size(), "%FT%TZ", gmtime(&now));
|
|
return date;
|
|
}
|
|
|
|
constexpr const char * LogLevelNames[]{"Debug", "Info", "Warning", "Error"};
|
|
constexpr LogLevel g_level = LogLevel::Debug;
|
|
constexpr bool syncLogFile = true;
|
|
|
|
namespace details {
|
|
|
|
constexpr const char* logPath(){
|
|
constexpr auto path = "/var/log/rublon-ssh.log";
|
|
return path;
|
|
}
|
|
|
|
static void doLog(LogLevel level, const char * line) noexcept {
|
|
|
|
static auto fp = std::unique_ptr< FILE, int (*)(FILE *) >(fopen(logPath(), "a"), fclose);
|
|
|
|
if(fp) {
|
|
fprintf(fp.get(), "%s [%s] %s\n", dateStr().data(), LogLevelNames[( int ) level], line);
|
|
if(syncLogFile)
|
|
sync();
|
|
}
|
|
}
|
|
} // namespace details
|
|
|
|
inline void log(LogLevel level, const char * line) noexcept {
|
|
if(level < g_level)
|
|
return;
|
|
details::doLog(level, line);
|
|
}
|
|
|
|
template < typename... Ti >
|
|
void log(LogLevel level, const char * fmt, Ti &&... ti) noexcept {
|
|
if(level < g_level)
|
|
return;
|
|
|
|
std::array< char, 1000 > line;
|
|
sprintf(line.data(), fmt, std::forward< Ti >(ti)...);
|
|
details::doLog(level, line.data());
|
|
}
|
|
|
|
template < typename T >
|
|
class NonOwningPtr {
|
|
T * object;
|
|
|
|
public:
|
|
constexpr NonOwningPtr(T * obj) : object{obj} {}
|
|
|
|
constexpr T * get() noexcept {
|
|
assert(object != nullptr);
|
|
return object;
|
|
}
|
|
constexpr const T * get() const noexcept {
|
|
assert(object != nullptr);
|
|
return object;
|
|
}
|
|
constexpr operator const T *() const noexcept {
|
|
return get();
|
|
}
|
|
constexpr operator T *() noexcept {
|
|
return get();
|
|
}
|
|
constexpr T * operator->() {
|
|
return get();
|
|
}
|
|
constexpr const T * operator->() const {
|
|
return get();
|
|
}
|
|
};
|
|
|
|
namespace details {
|
|
enum class ConversionError { OutOfRange, NotANumber };
|
|
inline tl::expected< std::uint32_t, ConversionError > to_uint32(std::string_view userinput) noexcept {
|
|
try {
|
|
return std::stoi(userinput.data());
|
|
} catch(const std::invalid_argument & e) {
|
|
return tl::make_unexpected(ConversionError::NotANumber);
|
|
} catch(const std::out_of_range & e) {
|
|
return tl::make_unexpected(ConversionError::OutOfRange);
|
|
}
|
|
}
|
|
|
|
inline bool to_bool(std::string_view value) {
|
|
/// TODO change to global allocator
|
|
auto * buf = ( char * ) alloca(value.size() + 1);
|
|
buf[value.size()] = '\0';
|
|
auto asciitolower = [](char in) { return in - ((in <= 'Z' && in >= 'A') ? ('Z' - 'z') : 0); };
|
|
|
|
std::transform(value.cbegin(), value.cend(), buf, asciitolower);
|
|
return strcmp(buf, "true") == 0;
|
|
}
|
|
|
|
static inline std::string_view ltrim(std::string_view s) {
|
|
while(s.length() && std::isspace(*s.begin()))
|
|
s.remove_prefix(1);
|
|
return s;
|
|
}
|
|
|
|
static inline std::string_view rtrim(std::string_view s) {
|
|
while(s.length() && std::isspace(*s.rbegin()))
|
|
s.remove_suffix(1);
|
|
return s;
|
|
}
|
|
|
|
static inline std::string_view trim(std::string_view s) {
|
|
return ltrim(rtrim(s));
|
|
}
|
|
|
|
template < typename Headers >
|
|
inline void headers(std::string_view data, Headers & headers) {
|
|
memory::StrictMonotonic_4k_HeapResource stackResource;
|
|
std::pmr::string tmp{&stackResource};
|
|
|
|
std::istringstream resp{};
|
|
resp.rdbuf()->pubsetbuf(const_cast< char * >(data.data()), data.size());
|
|
|
|
while(std::getline(resp, tmp) && !(trim(tmp).empty())) {
|
|
auto line = std::string_view(tmp);
|
|
auto index = tmp.find(':', 0);
|
|
if(index != std::string::npos) {
|
|
headers.insert({//
|
|
typename Headers::key_type{trim(line.substr(0, index)), headers.get_allocator()},
|
|
typename Headers::mapped_type{trim(line.substr(index + 1)), headers.get_allocator()}});
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
} // namespace rublon
|