#ifndef LOGGER_H #define LOGGER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include } namespace RspCrypto { class SMDPResponseGenerator; class SMDPResponseValidator; class Logger { public: enum class Level { DEBUG, INFO, WARNING, ERROR }; static void log(Level level, const std::string& message, const char* filename = nullptr, int line = 0) { auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); std::string levelStr; switch (level) { case Level::DEBUG: levelStr = "DEBUG"; break; case Level::INFO: levelStr = "INFO"; break; case Level::WARNING: levelStr = "WARNING"; break; case Level::ERROR: levelStr = "ERROR"; break; } std::stringstream ss; ss << "[" << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S") << "] " << std::setw(7) << std::left << levelStr; // Add filename and line information if provided if (filename) { // Extract just the base filename without the full path const char* base_filename = strrchr(filename, '/'); if (!base_filename) { base_filename = strrchr(filename, '\\'); // For Windows paths } base_filename = base_filename ? base_filename + 1 : filename; ss << " [" << base_filename << ":" << line << "]"; } ss << " " << message; std::cout << ss.str() << std::endl; } static void debug(const std::string& message, const char* filename = nullptr, int line = 0) { log(Level::DEBUG, message, filename, line); } static void info(const std::string& message, const char* filename = nullptr, int line = 0) { log(Level::INFO, message, filename, line); } static void warning(const std::string& message, const char* filename = nullptr, int line = 0) { log(Level::WARNING, message, filename, line); } static void error(const std::string& message, const char* filename = nullptr, int line = 0) { log(Level::ERROR, message, filename, line); } }; // Define macros to automatically include file and line information #define LOG_DEBUG(message) Logger::debug(message, __FILE__, __LINE__) #define LOG_INFO(message) Logger::info(message, __FILE__, __LINE__) #define LOG_WARNING(message) Logger::warning(message, __FILE__, __LINE__) #define LOG_ERROR(message) Logger::error(message, __FILE__, __LINE__) class OpenSSLError : public std::runtime_error { public: OpenSSLError(const std::string& message) : std::runtime_error(message + getOpenSSLErrors()) { } private: static std::string getOpenSSLErrors() { std::stringstream ss; unsigned long err; ss << " - OpenSSL Errors: "; while ((err = ERR_get_error()) != 0) { char* err_str = ERR_error_string(err, nullptr); ss << err_str << "; "; } return ss.str(); } }; class OpenSSLErrorHandler { public: // Get detailed error information from OpenSSL error queue static std::string getLastError() { std::stringstream errorStream; unsigned long errorCode; while ((errorCode = ERR_get_error()) != 0) { char errorBuffer[256]; ERR_error_string_n(errorCode, errorBuffer, sizeof(errorBuffer)); const char* library = ERR_lib_error_string(errorCode); #if OPENSSL_VERSION_NUMBER < 0x30000000 const char* function = ERR_func_error_string(errorCode); #endif const char* reason = ERR_reason_error_string(errorCode); errorStream << "OpenSSL Error:\n"; errorStream << " Code: 0x" << std::hex << errorCode << std::dec << "\n"; errorStream << " Library: " << (library ? library : "unknown") << "\n"; #if OPENSSL_VERSION_NUMBER < 0x30000000 errorStream << " Function: " << (function ? function : "unknown") << "\n"; #endif errorStream << " Reason: " << (reason ? reason : "unknown") << "\n"; errorStream << " Full: " << errorBuffer << "\n\n"; } return errorStream.str(); } static std::string getSSLError(SSL* ssl, int result) { int sslError = SSL_get_error(ssl, result); std::stringstream errorStream; errorStream << "SSL Error Details:\n"; errorStream << " Return code: " << result << "\n"; errorStream << " SSL error code: " << sslError << "\n"; errorStream << " SSL error type: " << getSSLErrorType(sslError) << "\n"; std::string queueErrors = getLastError(); if (!queueErrors.empty()) { errorStream << "\nError Queue:\n" << queueErrors; } return errorStream.str(); } static std::string getCertificateError(long verifyResult) { std::stringstream errorStream; if (verifyResult != X509_V_OK) { const char* errorString = X509_verify_cert_error_string(verifyResult); errorStream << "Certificate Verification Error:\n"; errorStream << " Code: " << verifyResult << "\n"; errorStream << " Description: " << (errorString ? errorString : "unknown") << "\n"; } return errorStream.str(); } static void printSSLErrors(const std::string& context = "") { if (!context.empty()) { std::cerr << "=== " << context << " ===" << std::endl; } std::string errors = getLastError(); if (!errors.empty()) { std::cerr << errors << std::endl; } else { std::cerr << "No OpenSSL errors in queue." << std::endl; } } private: static std::string getSSLErrorType(int sslError) { switch (sslError) { case SSL_ERROR_NONE: return "SSL_ERROR_NONE - No error"; case SSL_ERROR_SSL: return "SSL_ERROR_SSL - SSL library error"; case SSL_ERROR_WANT_READ: return "SSL_ERROR_WANT_READ - Need more data to read"; case SSL_ERROR_WANT_WRITE: return "SSL_ERROR_WANT_WRITE - Need to write data"; case SSL_ERROR_WANT_X509_LOOKUP: return "SSL_ERROR_WANT_X509_LOOKUP - X509 lookup required"; case SSL_ERROR_SYSCALL: return "SSL_ERROR_SYSCALL - System call error"; case SSL_ERROR_ZERO_RETURN: return "SSL_ERROR_ZERO_RETURN - Connection closed"; case SSL_ERROR_WANT_CONNECT: return "SSL_ERROR_WANT_CONNECT - Want connect"; case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT - Want accept"; default: return "Unknown SSL error type"; } } }; } // namespace RspCrypto #endif // LOGGER_H