diff --git a/.clang-tidy b/.clang-tidy index 168ad4c60..ca1bddbf8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -9,10 +9,12 @@ portability-*, readability-*, -clang-diagnostic-unused-command-line-argument, -cppcoreguidelines-avoid-magic-numbers, +-cppcoreguidelines-avoid-do-while, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-vararg, -modernize-use-trailing-return-type, +-misc-include-cleaner, -readability-function-cognitive-complexity, -readability-magic-numbers' diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index a9ad1a2c8..f29fb183b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -16,31 +16,22 @@ concurrency: cancel-in-progress: true jobs: - clang-tidy: + static-analysis: runs-on: ubuntu-latest - container: egecetinn/ubuntu2204 + container: egecetinn/alpine steps: - name: Checkout Code uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: submodules: recursive - - name: Prepare - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - - name: Configure - run: cmake -S . -B build - - name: Clang-tidy - run: run-clang-tidy -j`nproc` -p=build -header-filter=`pwd`/include/ src/*.cpp src/**/*.cpp - - format: - runs-on: ubuntu-latest - container: egecetinn/alpine - steps: - - name: Checkout Code - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Run clang-format run: clang-format include/**/*.hpp src/*.cpp src/**/*.cpp --verbose --dry-run --Werror - name: Run cppcheck - run: cppcheck -Iinclude/ src --verbose --enable=all --error-exitcode=1 --std=c++14 --language=c++ --suppressions-list=cppcheckSuppressions.txt --inline-suppr --check-level=exhaustive + run: cppcheck -Iinclude/ src --verbose --enable=all --error-exitcode=1 --std=c++17 --language=c++ --suppressions-list=cppcheckSuppressions.txt --inline-suppr --check-level=exhaustive + - name: Configure for clang-tidy + run: cmake -S . -B build + - name: Clang-tidy + run: run-clang-tidy -j`nproc` -p=build -header-filter=`pwd`/include/ src/*.cpp src/**/*.cpp memleak: runs-on: ubuntu-latest @@ -62,20 +53,25 @@ jobs: restore-keys: | memleak-ccache - name: Install Test Requirements - run: pip3 install -r tests/data/requirements.txt + run: | + python3 -m venv .venv + . .venv/bin/activate + pip3 install -r tests/data/requirements.txt - name: Configure run: cmake -DXXX_ENABLE_MEMLEAK_CHECK=ON -S . -B build - name: Build run: cmake --build build --parallel - name: Run tests - run: ctest --output-on-failure --test-dir build + run: | + . .venv/bin/activate + ctest --output-on-failure --test-dir build - name: Save ccache uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.ccache-restore.outputs.cache-primary-key }} - fuzzer: + fuzztests: runs-on: ubuntu-latest container: egecetinn/ubuntu2204 strategy: @@ -98,13 +94,18 @@ jobs: restore-keys: | ${{ matrix.sanitizer }}-ccache - name: Install Test Requirements - run: pip3 install -r tests/data/requirements.txt + run: | + python3 -m venv .venv + . .venv/bin/activate + pip3 install -r tests/data/requirements.txt - name: Configure run: cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DXXX_BUILD_UNITTESTS=OFF -DXXX_BUILD_FUZZTESTS=ON -DXXX_ENABLE_${{ matrix.sanitizer }}=ON -S . -B build - name: Build run: cmake --build build --parallel - name: Run tests - run: ctest --output-on-failure --test-dir build + run: | + . .venv/bin/activate + ctest --output-on-failure --test-dir build - name: Save ccache uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: @@ -117,18 +118,16 @@ jobs: name: regressions-${{ matrix.sanitizer }} path: build/tests/fuzztests/crash* - rockylinux: + unittests: runs-on: ubuntu-latest container: egecetinn/${{ matrix.image }} strategy: matrix: include: - image: rockylinux8 - - image: rockylinux8-icx - additional-flags: -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx - image: rockylinux9 - - image: rockylinux9-icx - additional-flags: -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx + - image: ubuntu2204 + - image: ubuntu2404 steps: - name: Checkout Code @@ -137,11 +136,6 @@ jobs: submodules: recursive - name: Prepare run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - - name: Setup Intel Compiler variables - if: contains(matrix.image, 'icx') - run: | - . /opt/intel/oneapi/setvars.sh - printenv >> $GITHUB_ENV - name: Restore ccache id: ccache-restore uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 @@ -152,14 +146,18 @@ jobs: restore-keys: | ${{ matrix.image }}-ccache - name: Install Test Requirements - run: pip3 install -r tests/data/requirements.txt + run: | + python3 -m venv .venv + . .venv/bin/activate + pip3 install -r tests/data/requirements.txt - name: Configure - run: cmake ${{ matrix.additional-flags }} -S . -B build + run: cmake -S . -B build - name: Build run: cmake --build build --parallel - name: Run Tests - id: test-step - run: ctest --output-on-failure --test-dir build + run: | + . .venv/bin/activate + ctest --output-on-failure --test-dir build - name: Save ccache uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b7bdd3fc4..f9cc529b7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,14 @@ on: permissions: contents: read +env: + CCACHE_DIR: ${{ github.workspace }}/.ccache + jobs: analyze: name: Analyze runs-on: ubuntu-latest + container: egecetinn/ubuntu2204 permissions: actions: read contents: read @@ -31,14 +35,27 @@ jobs: uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: submodules: recursive - - name: Prepare system - run: | - sudo apt update && sudo apt install libcurl4-openssl-dev -y + - name: Restore ccache + id: ccache-restore + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: | + ${{ env.CCACHE_DIR }} + key: codeql-ccache-${{ github.run_id }} + restore-keys: | + codeql-ccache - name: Initialize CodeQL uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: languages: ${{ matrix.language }} - - name: Autobuild - uses: github/codeql-action/autobuild@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + - name: Configure + run: cmake -S . -B build + - name: Build + run: cmake --build build --parallel - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 + - name: Save ccache + uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ steps.ccache-restore.outputs.cache-primary-key }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 5162b4e93..cc841840e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -13,8 +13,8 @@ jobs: deploy: permissions: contents: write # for JamesIves/github-pages-deploy-action to push changes in repo - runs-on: ubuntu-22.04 - container: egecetinn/ubuntu2204 + runs-on: ubuntu-latest + container: egecetinn/alpine steps: - name: Checkout repository uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 diff --git a/.gitignore b/.gitignore index 17074658b..5fac15f4b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ doc tests/data Testing .git +.venv .vscode .sentry-native diff --git a/CMakeLists.txt b/CMakeLists.txt index f0d13e802..924a1adc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ option(XXX_BUILD_FUZZTESTS "Build XXX fuzz tests" OFF) option(XXX_ENABLE_COVERAGE "Enables coverage report generation" OFF) option(XXX_ENABLE_MEMLEAK_CHECK "Enables Memory Leak Checker for unit tests" OFF) option(XXX_ENABLE_SYMBOL_GENERATION "Enables symbol generation for binaries (Requires breakpad)" OFF) -option(XXX_ENABLE_PACKAGING "Enables RPM packaging" OFF) +option(XXX_ENABLE_PACKAGING "Enables DEB/RPM packaging" OFF) # Set project properties set(PROJECT_VERSION_MAJOR 0) @@ -31,7 +31,7 @@ set(PROJECT_VERSION_TWEAK ${REVISION_VERSION}) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-${REVISION_VERSION}") message(STATUS "Compiling Version ${PROJECT_VERSION}") -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -165,32 +165,54 @@ install(FILES ${CMAKE_BINARY_DIR}/config.json DESTINATION ${CMAKE_INSTALL_PREFIX if(XXX_ENABLE_PACKAGING) set(EXE_PATH ${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}) set(SERVICE_NAME ${PROJECT_NAME}.service) - set(POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/postinst.sh) - set(POST_UNINSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/postuninst.sh) - set(PRE_UNINSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/preuninst.sh) + set(POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/postinst) + set(PRE_UNINSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/prerm) configure_file(${PROJECT_SOURCE_DIR}/scripts/template.service.in ${CMAKE_CURRENT_BINARY_DIR}/${SERVICE_NAME} @ONLY) - configure_file(${PROJECT_SOURCE_DIR}/scripts/post.sh.in ${POST_INSTALL_SCRIPT}) - configure_file(${PROJECT_SOURCE_DIR}/scripts/postun.sh.in ${POST_UNINSTALL_SCRIPT}) - configure_file(${PROJECT_SOURCE_DIR}/scripts/preun.sh.in ${PRE_UNINSTALL_SCRIPT}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.service DESTINATION ${CMAKE_INSTALL_PREFIX}/share) + configure_file(${PROJECT_SOURCE_DIR}/scripts/postinst.in ${POST_INSTALL_SCRIPT}) + configure_file(${PROJECT_SOURCE_DIR}/scripts/prerm.in ${PRE_UNINSTALL_SCRIPT}) - set(CPACK_GENERATOR "RPM") + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.service DESTINATION /lib/systemd/system) + + set(CPACK_PACKAGE_CONTACT "Ege Cetin ") + set(CPACK_PACKAGE_DESCRIPTION "C++ Application Template. It has already integrated a Telnet and ZeroMQ server to \ +receive commands, Crashpad handler to generate minidump, a Prometheus server to broadcast performance metrics. \ +Also, it can send logs to syslog using Spdlog, to a Sentry server and Grafana Loki instance") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Repository template for C++ applications") set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") set(CPACK_PACKAGE_RELEASE 1) set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md") - set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) + + # Debian package specific parameters + set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${POST_INSTALL_SCRIPT};${PRE_UNINSTALL_SCRIPT}") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcurl4 (>= 7.0), libspdlog1 (>= 1.8.0), libzmq5 (>= 4.0.0), systemd") + set(CPACK_DEBIAN_PACKAGE_SECTION "misc") + set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON) + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + + # RPM package specific parameters set(CPACK_RPM_PACKAGE_LICENSE "MIT") - set(CPACK_RPM_PACKAGE_REQUIRES_POSTUN "systemd") set(CPACK_RPM_PACKAGE_REQUIRES_PREUN "systemd") set(CPACK_RPM_PACKAGE_REQUIRES_POST "systemd") set(CPACK_RPM_PACKAGE_REQUIRES "libcurl >= 7.0, spdlog >= 1.8.0, zeromq >= 4.0.0") set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${POST_INSTALL_SCRIPT}) - set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${POST_UNINSTALL_SCRIPT}) set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE ${PRE_UNINSTALL_SCRIPT}) + include(CPack) + + if(XXX_ENABLE_SYMBOL_GENERATION) + # Create archive from symbols + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E tar cfvz ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-${PROJECT_VERSION}-syms.tar.gz + --format=gnutar ${CMAKE_BINARY_DIR}/syms + COMMENT "Creating tar gz archive from ${CMAKE_BINARY_DIR}/syms" + ) + endif() endif() # Enable test framework diff --git a/README.md b/README.md index 17068534e..d8a71145f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Project -CMake template to create new C++ applications with basic codes/interfaces are already defined. Requires a C++14 supported compiler. +CMake template to create new C++ applications with basic codes/interfaces are already defined. Requires a C++17 supported compiler. It provides the following features - Tracing @@ -90,5 +90,5 @@ Full dependency graph can be seen [here](doc/XXX-tree.svg) - coverage : Prepares coverage report - docs : Prepares documentation - dependency-graph : Prepares graphviz visualization of dependencies - - package : Prepares default packages + - package : Prepares default packages which includes deb/rpm package and symbols with a systemd service. You should specify the desired package type with -DCPACK_GENERATOR="DEB" (or "RPM") - test : Prepares gtest target diff --git a/include/connection/Http.hpp b/include/connection/Http.hpp index b7814b7c2..e964a3622 100644 --- a/include/connection/Http.hpp +++ b/include/connection/Http.hpp @@ -117,7 +117,7 @@ class HTTP { * Gets the host address of the object * @return The host address */ - const std::string &getHostAddress() const { return _hostAddr; } + [[nodiscard]] const std::string &getHostAddress() const { return _hostAddr; } /** * Sends a GET request diff --git a/include/connection/RawSocket.hpp b/include/connection/RawSocket.hpp index be10931a1..d2b5a667a 100644 --- a/include/connection/RawSocket.hpp +++ b/include/connection/RawSocket.hpp @@ -61,7 +61,7 @@ class RawSocket { * Returns the binded ethernet interface * @return std::string Name of the interface */ - const std::string &getInterfaceName() const { return _iFace; } + [[nodiscard]] const std::string &getInterfaceName() const { return _iFace; } /** * Writes data to the interface diff --git a/include/logging/Logger.hpp b/include/logging/Logger.hpp index b08de7e30..4bd9faf76 100644 --- a/include/logging/Logger.hpp +++ b/include/logging/Logger.hpp @@ -33,7 +33,7 @@ class MainLogger { * Returns pointer to mainlogger instance * @return std::shared_ptr Main logger */ - std::shared_ptr getLogger() const { return _mainLogger; } + [[nodiscard]] std::shared_ptr getLogger() const { return _mainLogger; } /** * Deconstructs the main logger diff --git a/include/logging/Loki.hpp b/include/logging/Loki.hpp index 5dd20da1c..cbaada33b 100644 --- a/include/logging/Loki.hpp +++ b/include/logging/Loki.hpp @@ -9,67 +9,64 @@ #include #include -namespace spdlog +namespace spdlog::sinks { - namespace sinks - { - // NOLINTBEGIN + // NOLINTBEGIN + /** + * A custom sink for spdlog that sends log messages to a Loki server. + * + * The loki_api_sink class is a custom sink for spdlog that sends log messages to a Loki server. + * It provides functionality to send log messages to a specified Loki server address. + * The log messages are sent using HTTP requests. + * + * @tparam Mutex The type of mutex to use for thread-safety. + */ + template class loki_api_sink : public base_sink { + public: /** - * A custom sink for spdlog that sends log messages to a Loki server. + * Constructs a loki_api_sink object with the specified Loki server address. * - * The loki_api_sink class is a custom sink for spdlog that sends log messages to a Loki server. - * It provides functionality to send log messages to a specified Loki server address. - * The log messages are sent using HTTP requests. - * - * @tparam Mutex The type of mutex to use for thread-safety. + * @param lokiAddress The address of the Loki server to send log messages to. */ - template class loki_api_sink : public base_sink { - public: - /** - * Constructs a loki_api_sink object with the specified Loki server address. - * - * @param lokiAddress The address of the Loki server to send log messages to. - */ - explicit loki_api_sink(const std::string &lokiAddress); + explicit loki_api_sink(const std::string &lokiAddress); - /** - * Destroys the loki_api_sink object. - */ - ~loki_api_sink(); + /** + * Destroys the loki_api_sink object. + */ + ~loki_api_sink(); - protected: - /** - * Sends the log message to the Loki server. - * - * This function is called by spdlog to send the log message to the Loki server. - * It is overridden from the base_sink class. - * - * @param msg The log message to be sent. - */ - void sink_it_(const details::log_msg &msg) override; + protected: + /** + * Sends the log message to the Loki server. + * + * This function is called by spdlog to send the log message to the Loki server. + * It is overridden from the base_sink class. + * + * @param msg The log message to be sent. + */ + void sink_it_(const details::log_msg &msg) override; - /** - * Flushes any buffered log messages. - * - * This function is called by spdlog to flush any buffered log messages. - * It is overridden from the base_sink class. - */ - void flush_() override; + /** + * Flushes any buffered log messages. + * + * This function is called by spdlog to flush any buffered log messages. + * It is overridden from the base_sink class. + */ + void flush_() override; - private: - bool _lokiAvailable{false}; - std::unique_ptr _connHandler; - std::string _basicInformation; + private: + bool _lokiAvailable{false}; + std::unique_ptr _connHandler; + std::string _basicInformation; - struct logInfo_t { - std::string level; - std::vector> logs; - }; - std::vector _internalLogBuffer; + struct logInfo_t { + std::string level; + std::vector> logs; }; + std::vector _internalLogBuffer; + }; - using loki_api_sink_mt = loki_api_sink; - using loki_api_sink_st = loki_api_sink; - // NOLINTEND - } // namespace sinks -} // namespace spdlog + using loki_api_sink_mt = loki_api_sink; + using loki_api_sink_st = loki_api_sink; + // NOLINTEND +} // namespace spdlog::sinks diff --git a/include/logging/Sentry.hpp b/include/logging/Sentry.hpp index 203452351..2e262a42e 100644 --- a/include/logging/Sentry.hpp +++ b/include/logging/Sentry.hpp @@ -6,58 +6,55 @@ #include #include -namespace spdlog +namespace spdlog::sinks { - namespace sinks - { - // NOLINTBEGIN + // NOLINTBEGIN + /** + * A sink for sending log messages to a Sentry server. + * + * This sink is used to send log messages to a Sentry server for error tracking and monitoring. + * It provides an interface for sending log messages and flushing the sink. + * + * @tparam Mutex The type of mutex to use for thread safety. + */ + template class sentry_api_sink : public base_sink { + public: /** - * A sink for sending log messages to a Sentry server. + * Constructs a Sentry API sink with the specified Sentry server address. * - * This sink is used to send log messages to a Sentry server for error tracking and monitoring. - * It provides an interface for sending log messages and flushing the sink. + * @param sentryAddress The address of the Sentry server. + */ + explicit sentry_api_sink(const std::string &sentryAddress); + + /** + * Destroys the Sentry API sink. + */ + ~sentry_api_sink(); + + protected: + /** + * Sends the log message to the Sentry server. + * + * This function is called for each log message that needs to be sent to the Sentry server. * - * @tparam Mutex The type of mutex to use for thread safety. + * @param msg The log message to be sent. */ - template class sentry_api_sink : public base_sink { - public: - /** - * Constructs a Sentry API sink with the specified Sentry server address. - * - * @param sentryAddress The address of the Sentry server. - */ - explicit sentry_api_sink(const std::string &sentryAddress); - - /** - * Destroys the Sentry API sink. - */ - ~sentry_api_sink(); - - protected: - /** - * Sends the log message to the Sentry server. - * - * This function is called for each log message that needs to be sent to the Sentry server. - * - * @param msg The log message to be sent. - */ - void sink_it_(const details::log_msg &msg) override; - - /** - * Flushes the sink. - * - * This function is called to flush any buffered log messages to the Sentry server. - */ - void flush_() override; - - private: - bool _sentryAvailable{false}; /**< Flag indicating if the Sentry server is available. */ - }; - - using sentry_api_sink_mt = sentry_api_sink; /**< Type alias for Sentry API sink with mutex. */ - using sentry_api_sink_st = - sentry_api_sink; /**< Type alias for Sentry API sink without mutex. */ - - // NOLINTEND - } // namespace sinks -} // namespace spdlog + void sink_it_(const details::log_msg &msg) override; + + /** + * Flushes the sink. + * + * This function is called to flush any buffered log messages to the Sentry server. + */ + void flush_() override; + + private: + bool _sentryAvailable{false}; /**< Flag indicating if the Sentry server is available. */ + }; + + using sentry_api_sink_mt = sentry_api_sink; /**< Type alias for Sentry API sink with mutex. */ + using sentry_api_sink_st = + sentry_api_sink; /**< Type alias for Sentry API sink without mutex. */ + + // NOLINTEND +} // namespace spdlog::sinks diff --git a/include/telnet/TelnetServer.hpp b/include/telnet/TelnetServer.hpp index 679592b2e..16a0b6789 100644 --- a/include/telnet/TelnetServer.hpp +++ b/include/telnet/TelnetServer.hpp @@ -85,7 +85,7 @@ class TelnetSession : public std::enable_shared_from_this { // Erase all characters on the current line and move prompt back to beginning of line void eraseLine(); // Echo back message - void echoBack(const char *buffer, u_long length); + void echoBack(const char *buffer, unsigned long length); // static void stripNVT(std::string &buffer); // Remove all escape characters from the line @@ -156,7 +156,7 @@ class TelnetServer : public std::enable_shared_from_this { * @return true If initialized * @return false otherwise */ - bool initialise(u_long listenPort, const std::shared_ptr &checkFlag, + bool initialise(unsigned long listenPort, const std::shared_ptr &checkFlag, std::string promptString = "", const std::shared_ptr ® = nullptr, const std::string &prependName = ""); @@ -175,7 +175,7 @@ class TelnetServer : public std::enable_shared_from_this { const VEC_SP_TelnetSession &sessions() const { return m_sessions; } bool interactivePrompt() const { return m_promptString.length() > 0; } - void promptString(const std::string &prompt) { m_promptString = prompt; } + void promptString(const std::string_view &prompt) { m_promptString = prompt; } const std::string &promptString() const { return m_promptString; } private: @@ -192,7 +192,7 @@ class TelnetServer : public std::enable_shared_from_this { /// Process new connections and messages void update(); - u_long m_listenPort{}; + unsigned long m_listenPort{}; Socket m_listenSocket{-1}; VEC_SP_TelnetSession m_sessions; bool m_initialised{false}; @@ -226,4 +226,4 @@ bool TelnetMessageCallback(const SP_TelnetSession &session, const std::string &l * @param[in] line Received message * @return std::string Command to complete */ -std::string TelnetTabCallback(const SP_TelnetSession &session, const std::string &line); +std::string TelnetTabCallback(const SP_TelnetSession &session, std::string_view line); diff --git a/include/utils/ErrorHelpers.hpp b/include/utils/ErrorHelpers.hpp index b766d9356..73ae2b9af 100644 --- a/include/utils/ErrorHelpers.hpp +++ b/include/utils/ErrorHelpers.hpp @@ -11,6 +11,11 @@ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) extern std::vector>> vCheckFlag; +// Alpine Linux incorrectly declares strerror_r +// https://stackoverflow.com/questions/41953104/strerror-r-is-incorrectly-declared-on-alpine-linux +char *checkError(int /*unused*/, char *buffer, int /*unused*/); +char *checkError(char *result, const char * /*unused*/, int /*unused*/); + /** * Converts errno to a readable string * @param[in] errVal errno value @@ -19,5 +24,5 @@ extern std::vector>> vC inline std::string getErrnoString(int errVal) { std::array buffer{}; - return strerror_r(errVal, buffer.data(), BUFSIZ); + return checkError(strerror_r(errVal, buffer.data(), BUFSIZ), buffer.data(), errVal); } diff --git a/include/utils/InputParser.hpp b/include/utils/InputParser.hpp index 679ab6e70..861935915 100644 --- a/include/utils/InputParser.hpp +++ b/include/utils/InputParser.hpp @@ -31,7 +31,7 @@ class InputParser { * @param[in] option Option to check * @return const std::string& Found command line input. Empty string if not found */ - const std::string &getCmdOption(const std::string &option) const + [[nodiscard]] const std::string &getCmdOption(const std::string &option) const { std::vector::const_iterator itr; itr = std::find(_tokens.begin(), _tokens.end(), option); @@ -47,7 +47,7 @@ class InputParser { * Gets all command line options * @return std::vector> All command line options */ - std::vector> getCmdOptions() const + [[nodiscard]] std::vector> getCmdOptions() const { std::vector> options; for (auto itr = _tokens.begin(); itr != _tokens.end(); ++itr) @@ -74,7 +74,7 @@ class InputParser { * @return true If the provided option is found * @return false If the provided option is not found */ - bool cmdOptionExists(const std::string &option) const + [[nodiscard]] bool cmdOptionExists(const std::string &option) const { return std::find(_tokens.begin(), _tokens.end(), option) != _tokens.end(); } diff --git a/include/utils/Tracer.hpp b/include/utils/Tracer.hpp index 7b29a5237..60cadc8d9 100644 --- a/include/utils/Tracer.hpp +++ b/include/utils/Tracer.hpp @@ -92,7 +92,7 @@ class Tracer { * Check if the crashpad_handler process is running * @return true if the crashpad_handler is running, false otherwise */ - bool isRunning() const; + [[nodiscard]] bool isRunning() const; /** * Check and restart the crashpad_handler process if it is not running diff --git a/include/zeromq/ZeroMQ.hpp b/include/zeromq/ZeroMQ.hpp index e08b23587..2c33e983f 100644 --- a/include/zeromq/ZeroMQ.hpp +++ b/include/zeromq/ZeroMQ.hpp @@ -25,7 +25,7 @@ class ZeroMQ { std::string _socketAddr; // Initializes class - void init(const std::shared_ptr &ctx, const zmq::socket_type &type, const std::string &addr, + void init(const std::shared_ptr &ctx, const zmq::socket_type &type, const std::string_view &addr, bool isBind); public: @@ -87,19 +87,19 @@ class ZeroMQ { * Get the reference of socket * @return const std::unique_ptr& */ - const std::unique_ptr &getSocket() const { return _socketPtr; } + [[nodiscard]] const std::unique_ptr &getSocket() const { return _socketPtr; } /** * Get the reference of context * @return const std::shared_ptr& */ - const std::shared_ptr &getContext() const { return _contextPtr; } + [[nodiscard]] const std::shared_ptr &getContext() const { return _contextPtr; } /** * Get the address of the socket * @return const std::string& Address of the socket */ - const std::string &getAddress() const { return _socketAddr; } + [[nodiscard]] const std::string &getAddress() const { return _socketAddr; } /** * Destroy the ZeroMQ class diff --git a/include/zeromq/ZeroMQServer.hpp b/include/zeromq/ZeroMQServer.hpp index 24065369d..d62bdfde5 100644 --- a/include/zeromq/ZeroMQServer.hpp +++ b/include/zeromq/ZeroMQServer.hpp @@ -75,7 +75,7 @@ class ZeroMQServer : private ZeroMQ, private ZeroMQMonitor { * Gets the message callback function * @return The message callback function */ - FPTR_MessageCallback messageCallback() const { return _m_messageCallback; } + [[nodiscard]] FPTR_MessageCallback messageCallback() const { return _m_messageCallback; } }; /** diff --git a/scripts/post.sh.in b/scripts/post.sh.in deleted file mode 100644 index 489d7dd38..000000000 --- a/scripts/post.sh.in +++ /dev/null @@ -1,19 +0,0 @@ -echo "Running post script for @PROJECT_NAME@ v@PROJECT_VERSION@" - -# If we're installing the package for the first time, copy -# the service file to the service unit directory. -# -# Don't touch the service file if we're upgrading the package. - -service_name=@SERVICE_NAME@ -if [ $1 -eq 1 ]; then - %{__install} -m644 $RPM_INSTALL_PREFIX/share/$service_name %{_unitdir}/$service_name -fi -%systemd_post $service_name - -# Only print about the service if it was installed for the first time. -if [ $1 -eq 1 ]; then - printf %"$COLUMNS"s |tr " " "-" - echo "$service_name was installed but wasn't started or enabled." - printf %"$COLUMNS"s |tr " " "-" -fi diff --git a/scripts/postinst.in b/scripts/postinst.in new file mode 100644 index 000000000..ac20b670e --- /dev/null +++ b/scripts/postinst.in @@ -0,0 +1,3 @@ +echo "Running post install script for @PROJECT_NAME@ v@PROJECT_VERSION@" + +systemctl enable @SERVICE_NAME@ diff --git a/scripts/postun.sh.in b/scripts/postun.sh.in deleted file mode 100644 index a93c21664..000000000 --- a/scripts/postun.sh.in +++ /dev/null @@ -1,11 +0,0 @@ -echo "Running postun script for @PROJECT_NAME@ v@PROJECT_VERSION@" - -# Use the standard systemd scriptlet. -service_name=@SERVICE_NAME@ -%systemd_postun_with_restart $service_name - -# Only remove the service file if we're removing the last -# version of the package. -if [ $1 -eq 0 ]; then - rm %{_unitdir}/$service_name -fi diff --git a/scripts/prerm.in b/scripts/prerm.in new file mode 100644 index 000000000..87e70b545 --- /dev/null +++ b/scripts/prerm.in @@ -0,0 +1,4 @@ +echo "Running pre-uninstall script for @PROJECT_NAME@ v@PROJECT_VERSION@" + +systemctl disable @SERVICE_NAME@ || true +systemctl stop @SERVICE_NAME@ || true diff --git a/scripts/preun.sh.in b/scripts/preun.sh.in deleted file mode 100644 index 318e1960d..000000000 --- a/scripts/preun.sh.in +++ /dev/null @@ -1,3 +0,0 @@ -echo "Running preun script for @PROJECT_NAME@ v@PROJECT_VERSION@" - -%systemd_preun @SERVICE_NAME@ diff --git a/scripts/runStaticAnalysis.sh b/scripts/runStaticAnalysis.sh index 55f216cf4..64890ffd9 100755 --- a/scripts/runStaticAnalysis.sh +++ b/scripts/runStaticAnalysis.sh @@ -9,7 +9,7 @@ echo "Running clang-format" clang-format include/**/*.hpp src/*.cpp src/**/*.cpp --verbose --dry-run --Werror echo "Running cppcheck" -cppcheck -Iinclude/ src --verbose --enable=all --error-exitcode=1 --std=c++14 --language=c++ --suppressions-list=cppcheckSuppressions.txt --inline-suppr +cppcheck -Iinclude/ src --verbose --enable=all --error-exitcode=1 --std=c++17 --language=c++ --suppressions-list=cppcheckSuppressions.txt --inline-suppr echo "Running clang-tidy" run-clang-tidy -j`nproc` -p=build -header-filter=`pwd`/include/ src/*.cpp src/**/*.cpp diff --git a/scripts/template.service.in b/scripts/template.service.in index def408dc3..42866ce23 100644 --- a/scripts/template.service.in +++ b/scripts/template.service.in @@ -3,7 +3,7 @@ Description=@PROJECT_NAME@ service [Service] Type=exec -ExecStart=@EXE_PATH@ --config @CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@/config.json +ExecStart=@EXE_PATH@ --config @CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@/config.json --enable-prometheus localhost:2212 --telnet-server 2215 --enable-zeromq tcp://127.0.0.1:2218 [Install] WantedBy=multi-user.target diff --git a/src/connection/RawSocket.cpp b/src/connection/RawSocket.cpp index 3231391a0..17ed5d076 100644 --- a/src/connection/RawSocket.cpp +++ b/src/connection/RawSocket.cpp @@ -83,6 +83,7 @@ int RawSocket::readData(unsigned char *data, size_t dataLen) { return -EPERM; } + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) socklen_t socketLen = sizeof(_addr); auto startTime = std::chrono::high_resolution_clock::now(); diff --git a/src/logging/Loki.cpp b/src/logging/Loki.cpp index 2c16e9409..d6d62f3d5 100644 --- a/src/logging/Loki.cpp +++ b/src/logging/Loki.cpp @@ -3,6 +3,7 @@ #include "Version.h" #include "utils/FileHelpers.hpp" +#include #include #include @@ -13,121 +14,117 @@ #include -namespace spdlog +namespace spdlog::sinks { - namespace sinks + template loki_api_sink::loki_api_sink(const std::string &lokiAddress) { - template loki_api_sink::loki_api_sink(const std::string &lokiAddress) + if (lokiAddress.empty()) { - if (lokiAddress.empty()) - { - return; - } + return; + } + + _connHandler = std::make_unique(lokiAddress); + + // Pre-allocate buffers + _internalLogBuffer.push_back({"debug", std::vector>()}); + _internalLogBuffer.push_back({"info", std::vector>()}); + _internalLogBuffer.push_back({"warn", std::vector>()}); + _internalLogBuffer.push_back({"error", std::vector>()}); + _internalLogBuffer.push_back({"critical", std::vector>()}); + + // Prepare information (Loki limits maximum number of labels with 15) + _basicInformation = ""; + _basicInformation += std::string(R"("release_version":"v)") + PROJECT_FULL_REVISION + "\","; + _basicInformation += std::string(R"("release_date":")") + PROJECT_BUILD_DATE + " " + PROJECT_BUILD_TIME + "\","; + _basicInformation += std::string(R"("compiler_name":")") + COMPILER_NAME + "\","; + _basicInformation += std::string(R"("compiler_version":")") + COMPILER_VERSION + "\","; + _basicInformation += std::string(R"("build":")") + BUILD_TYPE + "\","; + + // Parse hostname + std::array hostBuffer{}; + gethostname(hostBuffer.data(), BUFSIZ); + _basicInformation += std::string(R"("hostname":")") + hostBuffer.data() + "\","; + + // Parse CPU information + const std::string cpuInfoPath = "/proc/cpuinfo"; + std::string word; + + findFromFile(cpuInfoPath, "^siblings", word); + _basicInformation += std::string(R"("cpu_threadcount":")") + word + "\","; + findFromFile(cpuInfoPath, "^(cpu cores)", word); + _basicInformation += std::string(R"("cpu_corecount":")") + word + "\","; + findFromFile(cpuInfoPath, "^(model name)", word); + _basicInformation += std::string(R"("cpu_model":")") + word + "\","; + findFromFile(cpuInfoPath, "^vendor_id", word); + _basicInformation += std::string(R"("cpu_vendorid":")") + word + "\","; + + _lokiAvailable = true; + } + + template loki_api_sink::~loki_api_sink() = default; + + template void loki_api_sink::sink_it_(const details::log_msg &msg) + { + if (!_lokiAvailable) + { + return; + } - _connHandler = std::make_unique(lokiAddress); - - // Pre-allocate buffers - _internalLogBuffer.push_back({"debug", std::vector>()}); - _internalLogBuffer.push_back({"info", std::vector>()}); - _internalLogBuffer.push_back({"warn", std::vector>()}); - _internalLogBuffer.push_back({"error", std::vector>()}); - _internalLogBuffer.push_back({"critical", std::vector>()}); - - // Prepare information (Loki limits maximum number of labels with 15) - _basicInformation = ""; - _basicInformation += std::string(R"("release_version":"v)") + PROJECT_FULL_REVISION + "\","; - _basicInformation += - std::string(R"("release_date":")") + PROJECT_BUILD_DATE + " " + PROJECT_BUILD_TIME + "\","; - _basicInformation += std::string(R"("compiler_name":")") + COMPILER_NAME + "\","; - _basicInformation += std::string(R"("compiler_version":")") + COMPILER_VERSION + "\","; - _basicInformation += std::string(R"("build":")") + BUILD_TYPE + "\","; - - // Parse hostname - std::array hostBuffer{}; - gethostname(hostBuffer.data(), BUFSIZ); - _basicInformation += std::string(R"("hostname":")") + hostBuffer.data() + "\","; - - // Parse CPU information - const std::string cpuInfoPath = "/proc/cpuinfo"; - std::string word; - - findFromFile(cpuInfoPath, "^siblings", word); - _basicInformation += std::string(R"("cpu_threadcount":")") + word + "\","; - findFromFile(cpuInfoPath, "^(cpu cores)", word); - _basicInformation += std::string(R"("cpu_corecount":")") + word + "\","; - findFromFile(cpuInfoPath, "^(model name)", word); - _basicInformation += std::string(R"("cpu_model":")") + word + "\","; - findFromFile(cpuInfoPath, "^vendor_id", word); - _basicInformation += std::string(R"("cpu_vendorid":")") + word + "\","; - - _lokiAvailable = true; + if (msg.level >= spdlog::level::debug && msg.level <= spdlog::level::critical) + { + _internalLogBuffer[static_cast(msg.level) - 1].logs.push_back( + {std::to_string(msg.time.time_since_epoch().count()), + std::string(msg.payload.data(), msg.payload.size())}); } + } + + template void loki_api_sink::flush_() + { + bool flag = false; - template loki_api_sink::~loki_api_sink() = default; + // Prepare JSON + std::ostringstream sStream; - template void loki_api_sink::sink_it_(const details::log_msg &msg) + sStream << "{\"streams\":["; + for (auto &entry : _internalLogBuffer) { - if (!_lokiAvailable) + if (entry.logs.empty()) { - return; + continue; } - if (msg.level >= spdlog::level::debug && msg.level <= spdlog::level::critical) + if (flag) { - _internalLogBuffer[static_cast(msg.level) - 1].logs.push_back( - {std::to_string(msg.time.time_since_epoch().count()), - std::string(msg.payload.data(), msg.payload.size())}); + sStream << ","; } - } - - template void loki_api_sink::flush_() - { - bool flag = false; + flag = true; + sStream << "{\"stream\":{" << _basicInformation + R"("level":")" << entry.level << R"("},"values":[)"; - // Prepare JSON - std::ostringstream sStream; - - sStream << "{\"streams\":["; - for (auto &entry : _internalLogBuffer) + bool subflag = false; + for (const auto &subentry : entry.logs) { - if (entry.logs.empty()) - { - continue; - } - - if (flag) + if (subflag) { sStream << ","; } - flag = true; - sStream << "{\"stream\":{" << _basicInformation + R"("level":")" << entry.level << R"("},"values":[)"; - - bool subflag = false; - for (const auto &subentry : entry.logs) - { - if (subflag) - { - sStream << ","; - } - subflag = true; - sStream << "[\"" << subentry.first << "\",\"" << subentry.second << "\"]"; - } - sStream << "]}"; - - entry.logs.clear(); + subflag = true; + sStream << "[\"" << subentry.first << "\",\"" << subentry.second << "\"]"; } sStream << "]}"; - if (flag) - { - // Send request - std::string recvData; - HttpStatus::Code replyCode = HttpStatus::Code::xxx_max; - _connHandler->sendPOSTRequest("/loki/api/v1/push", sStream.str(), recvData, replyCode); - } + entry.logs.clear(); + } + sStream << "]}"; + + if (flag) + { + // Send request + std::string recvData; + HttpStatus::Code replyCode = HttpStatus::Code::xxx_max; + _connHandler->sendPOSTRequest("/loki/api/v1/push", sStream.str(), recvData, replyCode); } + } - template class loki_api_sink; - template class loki_api_sink; - } // namespace sinks -} // namespace spdlog + template class loki_api_sink; + template class loki_api_sink; +} // namespace spdlog::sinks diff --git a/src/logging/Sentry.cpp b/src/logging/Sentry.cpp index 76be84c82..d9c2bd514 100644 --- a/src/logging/Sentry.cpp +++ b/src/logging/Sentry.cpp @@ -3,6 +3,8 @@ #include "Version.h" #include "utils/FileHelpers.hpp" +#include + #include #include #include @@ -15,163 +17,159 @@ // MAC address length for character string constexpr int MAC_LEN = 18; -namespace spdlog +namespace spdlog::sinks { - namespace sinks + template sentry_api_sink::sentry_api_sink(const std::string &sentryAddress) { - template sentry_api_sink::sentry_api_sink(const std::string &sentryAddress) + if (sentryAddress.empty()) { - if (sentryAddress.empty()) - { - return; - } - _sentryAvailable = true; - - // Set options - sentry_options_t *sentryOptions = sentry_options_new(); - sentry_options_set_release(sentryOptions, PROJECT_FULL_REVISION); - sentry_options_set_dsn(sentryOptions, sentryAddress.c_str()); - - // Init - sentry_init(sentryOptions); - - // Tags - sentry_set_tag("compiler.name", COMPILER_NAME); - sentry_set_tag("compiler.version", COMPILER_VERSION); - sentry_set_tag("build", BUILD_TYPE); - - // Context: Version - std::string versionBuffer; - const sentry_value_t versionContext = sentry_value_new_object(); - versionBuffer = "v" + std::string(PROJECT_FULL_REVISION); - sentry_value_set_by_key(versionContext, PROJECT_NAME, sentry_value_new_string(versionBuffer.c_str())); - versionBuffer = std::string(PROJECT_BUILD_DATE) + " " + PROJECT_BUILD_TIME; - sentry_value_set_by_key(versionContext, "Release Date", sentry_value_new_string(versionBuffer.c_str())); - /* ################################################################################### */ - /* ############################# MAKE MODIFICATIONS HERE ############################# */ - /* ################################################################################### */ - - /* ################################################################################### */ - /* ################################ END MODIFICATIONS ################################ */ - /* ################################################################################### */ - - sentry_set_context("Version", versionContext); - - // Context: Host - std::array hostBuffer{}; - gethostname(hostBuffer.data(), BUFSIZ); - const sentry_value_t hostContext = sentry_value_new_object(); - sentry_value_set_by_key(hostContext, "Hostname", sentry_value_new_string(hostBuffer.data())); - - // Parse CPU information - const std::string cpuInfoPath = "/proc/cpuinfo"; - std::string word; - - findFromFile(cpuInfoPath, "^siblings", word); - sentry_value_set_by_key(hostContext, "Thread count", sentry_value_new_string(word.c_str())); - findFromFile(cpuInfoPath, "^(cpu cores)", word); - sentry_value_set_by_key(hostContext, "Core count", sentry_value_new_string(word.c_str())); - findFromFile(cpuInfoPath, "^(model name)", word); - sentry_value_set_by_key(hostContext, "Model", sentry_value_new_string(word.c_str())); - findFromFile(cpuInfoPath, "^vendor_id", word); - sentry_value_set_by_key(hostContext, "Vendor ID", sentry_value_new_string(word.c_str())); - - sentry_set_context("Host", hostContext); - - // Context: Network - const sentry_value_t networkContext = sentry_value_new_object(); - - ifaddrs *ifaddr = nullptr; - if (getifaddrs(&ifaddr) != -1) + return; + } + _sentryAvailable = true; + + // Set options + sentry_options_t *sentryOptions = sentry_options_new(); + sentry_options_set_release(sentryOptions, PROJECT_FULL_REVISION); + sentry_options_set_dsn(sentryOptions, sentryAddress.c_str()); + + // Init + sentry_init(sentryOptions); + + // Tags + sentry_set_tag("compiler.name", COMPILER_NAME); + sentry_set_tag("compiler.version", COMPILER_VERSION); + sentry_set_tag("build", BUILD_TYPE); + + // Context: Version + std::string versionBuffer; + const sentry_value_t versionContext = sentry_value_new_object(); + versionBuffer = "v" + std::string(PROJECT_FULL_REVISION); + sentry_value_set_by_key(versionContext, PROJECT_NAME, sentry_value_new_string(versionBuffer.c_str())); + versionBuffer = std::string(PROJECT_BUILD_DATE) + " " + PROJECT_BUILD_TIME; + sentry_value_set_by_key(versionContext, "Release Date", sentry_value_new_string(versionBuffer.c_str())); + /* ################################################################################### */ + /* ############################# MAKE MODIFICATIONS HERE ############################# */ + /* ################################################################################### */ + + /* ################################################################################### */ + /* ################################ END MODIFICATIONS ################################ */ + /* ################################################################################### */ + + sentry_set_context("Version", versionContext); + + // Context: Host + std::array hostBuffer{}; + gethostname(hostBuffer.data(), BUFSIZ); + const sentry_value_t hostContext = sentry_value_new_object(); + sentry_value_set_by_key(hostContext, "Hostname", sentry_value_new_string(hostBuffer.data())); + + // Parse CPU information + const std::string cpuInfoPath = "/proc/cpuinfo"; + std::string word; + + findFromFile(cpuInfoPath, "^siblings", word); + sentry_value_set_by_key(hostContext, "Thread count", sentry_value_new_string(word.c_str())); + findFromFile(cpuInfoPath, "^(cpu cores)", word); + sentry_value_set_by_key(hostContext, "Core count", sentry_value_new_string(word.c_str())); + findFromFile(cpuInfoPath, "^(model name)", word); + sentry_value_set_by_key(hostContext, "Model", sentry_value_new_string(word.c_str())); + findFromFile(cpuInfoPath, "^vendor_id", word); + sentry_value_set_by_key(hostContext, "Vendor ID", sentry_value_new_string(word.c_str())); + + sentry_set_context("Host", hostContext); + + // Context: Network + const sentry_value_t networkContext = sentry_value_new_object(); + + if (ifaddrs *ifaddr = nullptr; getifaddrs(&ifaddr) != -1) + { + // Iterate interfaces + for (ifaddrs *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - // Iterate interfaces - for (ifaddrs *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + if (ifa->ifa_addr == nullptr) + { + continue; + } + + switch (ifa->ifa_addr->sa_family) { - if (ifa->ifa_addr == nullptr) + case AF_INET: + if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) { - continue; + std::array host{}; + inet_ntop(AF_INET, &(reinterpret_cast(ifa->ifa_addr))->sin_addr, host.data(), + INET_ADDRSTRLEN); + sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv4").c_str(), + sentry_value_new_string(host.data())); } - - switch (ifa->ifa_addr->sa_family) + break; + case AF_INET6: + if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) { - case AF_INET: - if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) - { - std::array host{}; - inet_ntop(AF_INET, &(reinterpret_cast(ifa->ifa_addr))->sin_addr, host.data(), - INET_ADDRSTRLEN); - sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv4").c_str(), - sentry_value_new_string(host.data())); - } - break; - case AF_INET6: - if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) + std::array host{}; + inet_ntop(AF_INET6, &(reinterpret_cast(ifa->ifa_addr))->sin6_addr, host.data(), + INET6_ADDRSTRLEN); + sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv6").c_str(), + sentry_value_new_string(host.data())); + } + break; + case AF_PACKET: + if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) + { + std::array host{}; + const auto *sock = reinterpret_cast(ifa->ifa_addr); + if (snprintf(host.data(), MAC_LEN, "%02x:%02x:%02x:%02x:%02x:%02x", sock->sll_addr[0], + sock->sll_addr[1], sock->sll_addr[2], sock->sll_addr[3], sock->sll_addr[4], + sock->sll_addr[5]) > 0) { - std::array host{}; - inet_ntop(AF_INET6, &(reinterpret_cast(ifa->ifa_addr))->sin6_addr, - host.data(), INET6_ADDRSTRLEN); - sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".ipv6").c_str(), + sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".mac").c_str(), sentry_value_new_string(host.data())); } - break; - case AF_PACKET: - if (((ifa->ifa_flags & IFF_PROMISC) != 0) || ((ifa->ifa_flags & IFF_UP) != 0)) - { - std::array host{}; - const auto *sock = reinterpret_cast(ifa->ifa_addr); - if (snprintf(host.data(), MAC_LEN, "%02x:%02x:%02x:%02x:%02x:%02x", sock->sll_addr[0], - sock->sll_addr[1], sock->sll_addr[2], sock->sll_addr[3], sock->sll_addr[4], - sock->sll_addr[5]) > 0) - { - sentry_value_set_by_key(networkContext, (std::string(ifa->ifa_name) + ".mac").c_str(), - sentry_value_new_string(host.data())); - } - } - break; - default: - break; } + break; + default: + break; } - freeifaddrs(ifaddr); } - sentry_set_context("Network", networkContext); + freeifaddrs(ifaddr); } + sentry_set_context("Network", networkContext); + } - template sentry_api_sink::~sentry_api_sink() { sentry_close(); } + template sentry_api_sink::~sentry_api_sink() { sentry_close(); } - template void sentry_api_sink::sink_it_(const details::log_msg &msg) + template void sentry_api_sink::sink_it_(const details::log_msg &msg) + { + if (!_sentryAvailable) { - if (!_sentryAvailable) - { - return; - } - switch (msg.level) - { - case spdlog::level::warn: - sentry_capture_event(sentry_value_new_message_event( - SENTRY_LEVEL_WARNING, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); - break; - case spdlog::level::err: - sentry_capture_event(sentry_value_new_message_event( - SENTRY_LEVEL_ERROR, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); - break; - case spdlog::level::critical: - sentry_capture_event(sentry_value_new_message_event( - SENTRY_LEVEL_FATAL, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); - break; - case spdlog::level::trace: - case spdlog::level::debug: - case spdlog::level::info: - case spdlog::level::off: - // For lower levels, do nothing for now. But you can easily handle them here. - default: - break; - } + return; + } + switch (msg.level) + { + case spdlog::level::warn: + sentry_capture_event(sentry_value_new_message_event( + SENTRY_LEVEL_WARNING, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); + break; + case spdlog::level::err: + sentry_capture_event(sentry_value_new_message_event( + SENTRY_LEVEL_ERROR, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); + break; + case spdlog::level::critical: + sentry_capture_event(sentry_value_new_message_event( + SENTRY_LEVEL_FATAL, "main", std::string(msg.payload.data(), msg.payload.size()).c_str())); + break; + case spdlog::level::trace: + case spdlog::level::debug: + case spdlog::level::info: + case spdlog::level::off: + // For lower levels, do nothing for now. But you can easily handle them here. + default: + break; } + } - template void sentry_api_sink::flush_() {} + template void sentry_api_sink::flush_() {} - template class sentry_api_sink; - template class sentry_api_sink; - } // namespace sinks -} // namespace spdlog + template class sentry_api_sink; + template class sentry_api_sink; +} // namespace spdlog::sinks diff --git a/src/main.cpp b/src/main.cpp index afd0d7e60..881217d55 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,16 +19,19 @@ constexpr uintmax_t alarmInterval = 1; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) volatile sig_atomic_t interruptFlag = 0; -// Default SIGALRM function -static void alarmFunc(int /*unused*/) +namespace { - alarm(alarmInterval); + // Default SIGALRM function + void alarmFunc(int /*unused*/) + { + alarm(alarmInterval); - // Clear all flags - std::for_each(vCheckFlag.begin(), vCheckFlag.end(), [](auto &entry) { entry.second->clear(); }); -} + // Clear all flags + std::for_each(vCheckFlag.begin(), vCheckFlag.end(), [](auto &entry) { entry.second->clear(); }); + } -static void interruptFunc(int /*unused*/) { interruptFlag = 1; } + void interruptFunc(int /*unused*/) { interruptFlag = 1; } +} // namespace int main(int argc, char **argv) { diff --git a/src/metrics/ProcessMetrics.cpp b/src/metrics/ProcessMetrics.cpp index 8dba9f8bb..45409a447 100644 --- a/src/metrics/ProcessMetrics.cpp +++ b/src/metrics/ProcessMetrics.cpp @@ -54,8 +54,8 @@ double ProcessMetrics::getCpuUsage() struct tms nowCpu {}; auto nowCpuTime = times(&nowCpu); - double usage = 100.0 * static_cast(nowCpu.tms_utime - _oldCpu.tms_utime) / - static_cast(nowCpuTime - _oldCpuTime); + const double usage = 100.0 * static_cast(nowCpu.tms_utime - _oldCpu.tms_utime) / + static_cast(nowCpuTime - _oldCpuTime); std::swap(_oldCpu, nowCpu); std::swap(_oldCpuTime, nowCpuTime); @@ -90,9 +90,9 @@ void ProcessMetrics::update() _pMemory->Set(static_cast(getMemoryUsage())); _pPageFaults->Set(static_cast(getPageFaults())); _pCpuUsage->Set(getCpuUsage()); - auto diskIO = getDiskIO(); - _pDiskRead->Set(static_cast(diskIO.first)); - _pDiskWrite->Set(static_cast(diskIO.second)); + auto [diskRead, diskWrite] = getDiskIO(); + _pDiskRead->Set(static_cast(diskRead)); + _pDiskWrite->Set(static_cast(diskWrite)); _pThreadCount->Set(static_cast(getThreadCount())); _pFileDescriptorCount->Set(static_cast(getFileDescriptorCount())); } diff --git a/src/metrics/PrometheusServer.cpp b/src/metrics/PrometheusServer.cpp index fc7b97037..45ee27372 100644 --- a/src/metrics/PrometheusServer.cpp +++ b/src/metrics/PrometheusServer.cpp @@ -18,7 +18,7 @@ PrometheusServer::PrometheusServer(const std::string &serverAddr) _infoFamily->Add({{"init_time", date::format("%FT%TZ", date::floor( std::chrono::high_resolution_clock::now()))}}); - _infoFamily->Add({{"version", PROJECT_FULL_VERSION_STRING}}); + _infoFamily->Add({{"version", PROJECT_FULL_REVISION}}); _vRegister.emplace_back(std::numeric_limits::max(), reg); _mainExposer->RegisterCollectable(reg); @@ -26,13 +26,13 @@ PrometheusServer::PrometheusServer(const std::string &serverAddr) std::shared_ptr PrometheusServer::getRegistry(uint64_t regId) { - const std::lock_guard guard(_guardLock); + const std::scoped_lock guard(_guardLock); - auto iter = std::find_if( - _vRegister.begin(), _vRegister.end(), - [regId](const std::pair> &val) { return regId == val.first; }); - - if (iter != _vRegister.end()) + if (auto iter = std::find_if(_vRegister.begin(), _vRegister.end(), + [regId](const std::pair> &val) { + return regId == val.first; + }); + iter != _vRegister.end()) { return iter->second; } @@ -47,7 +47,7 @@ std::shared_ptr PrometheusServer::createNewRegistry() std::shared_ptr PrometheusServer::createNewRegistry(uint64_t ®Id) { - const std::lock_guard guard(_guardLock); + const std::scoped_lock guard(_guardLock); // Create registry auto reg = std::make_shared(); @@ -66,7 +66,7 @@ bool PrometheusServer::deleteRegistry(uint64_t regId) return false; } - const std::lock_guard guard(_guardLock); + const std::scoped_lock guard(_guardLock); _vRegister.erase(std::remove_if( _vRegister.begin(), _vRegister.end(), diff --git a/src/telnet/TelnetServer.cpp b/src/telnet/TelnetServer.cpp index 43b2e9c86..c92bd8e83 100644 --- a/src/telnet/TelnetServer.cpp +++ b/src/telnet/TelnetServer.cpp @@ -6,11 +6,15 @@ #include +#include +#include #include #include #include #include +#include + // Invalid socket identifier for readability constexpr int INVALID_SOCKET = -1; // Receive buffer length @@ -162,8 +166,7 @@ void TelnetSession::sendLine(std::string data) } data.append("\r\n"); - const ssize_t sendBytes = send(m_socket, data.c_str(), data.length(), 0); - if (sendBytes > 0) + if (auto sendBytes = send(m_socket, data.c_str(), data.length(), 0) > 0) { stats.uploadBytes += static_cast(sendBytes); } @@ -199,11 +202,10 @@ void TelnetSession::markTimeout() lastSeenTime = std::chrono::system_clock::time_point(std::chrono::duration(0)); } -void TelnetSession::echoBack(const char *buffer, u_long length) +void TelnetSession::echoBack(const char *buffer, unsigned long length) { // If you are an NVT command (i.e. first it of data is 255) then ignore the echo back - const auto firstItem = static_cast(*buffer); - if (firstItem == ASCII_NBSP) + if (static_cast(*buffer) == ASCII_NBSP) { return; } @@ -223,7 +225,7 @@ void TelnetSession::initialise() stats.connectTime = std::chrono::high_resolution_clock::now(); // Set the connection to be non-blocking - u_long iMode = 1; + unsigned long iMode = 1; ioctl(m_socket, FIONBIO, &iMode); // Set NVT mode to say that I will echo back characters. @@ -549,13 +551,13 @@ TelnetServer::~TelnetServer() } catch (const std::exception &e2) { - std::cerr << "Telnet server destructor and also logger thrown an exception: " << e.what() << std::endl - << e2.what() << std::endl; + std::cerr << "Telnet server destructor and also logger thrown an exception: " << e.what() << '\n' + << e2.what() << '\n'; } } } -bool TelnetServer::initialise(u_long listenPort, const std::shared_ptr &checkFlag, +bool TelnetServer::initialise(unsigned long listenPort, const std::shared_ptr &checkFlag, std::string promptString, const std::shared_ptr ®, const std::string &prependName) { @@ -591,8 +593,7 @@ bool TelnetServer::initialise(u_long listenPort, const std::shared_ptrsendLine(""); session->sendLine("Available commands:"); session->sendLine(""); - for (const auto &entry : telnetCommands) + for (const auto &[command, info] : telnetCommands) { std::array buffer{'\0'}; - if (snprintf(buffer.data(), BUFSIZ, "%-25s : %s", entry.first.c_str(), entry.second.c_str()) > 0) + if (snprintf(buffer.data(), BUFSIZ, "%-25s : %s", command.c_str(), info.c_str()) > 0) { session->sendLine(buffer.data()); } @@ -836,11 +837,11 @@ bool TelnetMessageCallback(const SP_TelnetSession &session, const std::string &l session->sendLine(TELNET_CLEAR_SCREEN); return true; case constHasher("status"): - for (const auto &entry : vCheckFlag) + for (const auto &[service, statusFlag] : vCheckFlag) { std::ostringstream oss; - oss << std::left << std::setfill('.') << std::setw(KEY_WIDTH) << entry.first + " " << std::setw(VAL_WIDTH) - << std::right << (entry.second->_M_i ? " OK" : " Not Active"); + oss << std::left << std::setfill('.') << std::setw(KEY_WIDTH) << service + " " << std::setw(VAL_WIDTH) + << std::right << (statusFlag->_M_i ? " OK" : " Not Active"); session->sendLine(oss.str()); } return true; @@ -862,19 +863,19 @@ bool TelnetMessageCallback(const SP_TelnetSession &session, const std::string &l } } -std::string TelnetTabCallback(const SP_TelnetSession &session, const std::string &line) +std::string TelnetTabCallback(const SP_TelnetSession &session, std::string_view line) { std::string retval; size_t ctr = 0; std::ostringstream sStream; - for (const auto &entry : telnetCommands) + for (const auto &[command, info] : telnetCommands) { - if (entry.first.rfind(line, 0) == 0) + if (command.rfind(line, 0) == 0) { ++ctr; - retval = entry.first; - sStream << entry.first << std::setw(KEY_WIDTH); + retval = command; + sStream << command << std::setw(KEY_WIDTH); } } // Send suggestions if found any. If there is only one command retval will invoke completion diff --git a/src/utils/ErrorHelpers.cpp b/src/utils/ErrorHelpers.cpp index 7f30598fa..412e0451c 100644 --- a/src/utils/ErrorHelpers.cpp +++ b/src/utils/ErrorHelpers.cpp @@ -2,3 +2,7 @@ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) std::vector>> vCheckFlag; + +char *checkError(int /*unused*/, char *buffer, int /*unused*/) { return buffer; } + +char *checkError(char *result, const char * /*unused*/, int /*unused*/) { return result; } diff --git a/src/utils/Tracer.cpp b/src/utils/Tracer.cpp index f4ae90d19..57b595f97 100644 --- a/src/utils/Tracer.cpp +++ b/src/utils/Tracer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -21,11 +22,11 @@ constexpr int SLEEP_INTERVAL_MS = 50; void Tracer::startHandler() { // Path to crashpad executable - base::FilePath handler(_handlerPath); + const base::FilePath handler(_handlerPath); // Must be writable or crashpad_handler will crash - base::FilePath reportsDir(_reportPath); - base::FilePath metricsDir(_reportPath); + const base::FilePath reportsDir(_reportPath); + const base::FilePath metricsDir(_reportPath); // Initialize Crashpad database auto database = crashpad::CrashReportDatabase::Initialize(reportsDir); @@ -84,7 +85,7 @@ bool Tracer::checkSocketIsRunning(int sockId) socklen_t len = sizeof(error); char buff = 0; - int result = getsockopt(sockId, SOL_SOCKET, SO_ERROR, &error, &len); + const int result = getsockopt(sockId, SOL_SOCKET, SO_ERROR, &error, &len); return result == 0 && error == 0 && recv(sockId, &buff, 1, MSG_PEEK | MSG_DONTWAIT) != 0; } @@ -157,12 +158,12 @@ void Tracer::dumpSharedLibraryInfo(const std::string &filePath) if (pathname.find(".so") != std::string::npos && perms.find("r-x") != std::string::npos) { // The address field is in the form of start-end, we only need the start address - std::string start = address.substr(0, address.find('-')); + const std::string start = address.substr(0, address.find('-')); // Convert the start address from hexadecimal string to unsigned long - unsigned long addr = std::stoul(start, nullptr, 16); + const unsigned long addr = std::stoul(start, nullptr, 16); - ofile << pathname << " " << addr << std::endl; + ofile << pathname << " " << addr << '\n'; } } } diff --git a/src/zeromq/ZeroMQ.cpp b/src/zeromq/ZeroMQ.cpp index 3df79b6f8..e22069c8d 100644 --- a/src/zeromq/ZeroMQ.cpp +++ b/src/zeromq/ZeroMQ.cpp @@ -1,6 +1,7 @@ #include "zeromq/ZeroMQ.hpp" #include +#include #include #include @@ -10,8 +11,8 @@ constexpr int ZEROMQ_MSG_TIMEOUT_MS = 1000; // ZeroMQ heartbeat timeout in milliseconds constexpr int ZEROMQ_HEARTBEAT_TIMEOUT_MS = 1000; -void ZeroMQ::init(const std::shared_ptr &ctx, const zmq::socket_type &type, const std::string &addr, - bool isBind) +void ZeroMQ::init(const std::shared_ptr &ctx, const zmq::socket_type &type, + const std::string_view &addr, bool isBind) { _contextPtr = ctx; _socketAddr = addr; @@ -86,7 +87,8 @@ std::vector ZeroMQ::recvMessages() } else { - zmq::recv_multipart(*_socketPtr, std::back_inserter(recvMsgs)); + auto nMsgs = zmq::recv_multipart(*_socketPtr, std::back_inserter(recvMsgs)); + spdlog::debug("Received {} messages", nMsgs.value_or(0)); } return recvMsgs; } @@ -103,11 +105,7 @@ size_t ZeroMQ::sendMessages(std::vector &msg) res = zmq::send_multipart(*_socketPtr, msg); } - if (res.has_value()) - { - return res.value(); - } - return 0; + return res.value_or(0); } ZeroMQ::~ZeroMQ() @@ -125,8 +123,8 @@ ZeroMQ::~ZeroMQ() catch (const std::exception &e2) { std::cerr << "Error while stopping ZeroMQ connection and logger for connection " << _socketAddr << " (" - << e.what() << ")" << std::endl - << e2.what() << std::endl; + << e.what() << ")" << '\n' + << e2.what() << '\n'; } } }