From ceac077637d147b54abeeb4f0154bf152ba13138 Mon Sep 17 00:00:00 2001 From: Mihai Moldovan Date: Sat, 30 Sep 2017 16:58:16 +0200 Subject: nxcomp: add basic logging_test utility in test subdirectory. Needs more sophisticated features to actually test stuff correctly. --- nxcomp/test/logging_test.cpp | 224 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 nxcomp/test/logging_test.cpp (limited to 'nxcomp/test/logging_test.cpp') diff --git a/nxcomp/test/logging_test.cpp b/nxcomp/test/logging_test.cpp new file mode 100644 index 000000000..7e2d7d213 --- /dev/null +++ b/nxcomp/test/logging_test.cpp @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logging_test.h" + +Faulty_Logger faulty_logger; +NXLog good_logger; + +void print_sigmask () { + sigset_t orig_mask; + sigemptyset (&orig_mask); + + pthread_sigmask (SIG_SETMASK, NULL, &orig_mask); + + bool empty = true; + for (std::size_t i = 0; i < NSIG; ++i) { + if (sigismember (&orig_mask, i)) { + nxdbg_good << "Signal i (" << i << ") in signal mask." << std::endl; + empty = false; + } + } + + if (empty) { + nxdbg_good << "Signal mask empty."; + } +} + +void* log_task (void* /* unused */) { + /* print_sigmask (); */ + + for (std::size_t i = 0; i < 10; ++i) { + nxinfo << "Log message " << i << std::endl; + } +} + +void sig_handler (int signo) { + nxinfo << "Received signal " << signo << std::endl; +} + +void setup_faulty_logger () { + faulty_logger.log_level (true); + faulty_logger.log_unix_time (false); + faulty_logger.log_time (true); + faulty_logger.log_location (true); + faulty_logger.log_thread_id (true); + faulty_logger.level (NXDEBUG); +} + +void setup_good_logger () { + good_logger.log_level (true); + good_logger.log_unix_time (false); + good_logger.log_time (true); + good_logger.log_location (true); + good_logger.log_thread_id (true); + good_logger.level (NXDEBUG); +} + +pthread_t spawn_thread () { + pthread_t thread_id; + int pthread_ret; + + sigset_t block_mask, orig_mask; + sigemptyset (&orig_mask); + sigfillset (&block_mask); + + pthread_sigmask (SIG_BLOCK, &block_mask, &orig_mask); + + pthread_ret = pthread_create (&thread_id, NULL, log_task, NULL); + + pthread_sigmask (SIG_SETMASK, &orig_mask, NULL); + + return (thread_id); +} + +void install_signal_handler () { + struct sigaction sa; + sa.sa_handler = sig_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (-1 == sigaction (SIGUSR1, &sa, NULL)) { + nxerr_good << "Unable to install signal handler!" << std::endl; + } + else { + nxdbg_good << "Signal handler registered successfully for SIGUSR1." << std::endl; + } +} + +void killing_process_work (pid_t parent_pid) { + /* Seed PRNG. */ + std::srand (std::time (0)); + + for (std::size_t i = 0; i < 25; ++i) { + /* Sleep for 4 seconds + some random number up to a second. */ + std::size_t rand_add = (std::rand () % 1000000); + usleep (4000000 + rand_add); + + /* Send SIGUSR1 to parent process. */ + nxdbg_good << "Sending SIGUSR1 (" << SIGUSR1 << ") to parent_pid (" << parent_pid << ")" << std::endl; + + if (kill (parent_pid, SIGUSR1)) { + int saved_errno = errno; + nxerr_good << "Failed to deliver signal to parent, aborting." << std::endl; + nxerr_good << "Error " << saved_errno << ": " << strerror (saved_errno) << std::endl; + exit (EXIT_FAILURE); + } + } + + exit (EXIT_SUCCESS); +} + +void killing_process_init (int argc, char **argv) { + /* We're in the "killing process". */ + pid_t parent_pid = getppid (); + + setup_good_logger (); + + for (std::size_t i = 0; i < argc; ++i) { + nxdbg_good << "argv[" << i << "]: " << argv[i] << std::endl; + } + + char *end = NULL; + + errno = 0; + long parent_pid_check = std::strtol (argv[1], &end, 0); + + if ((errno == ERANGE) && (parent_pid_check == LONG_MAX)) { + /* Overflow, handle gracefully. */ + parent_pid_check = 1; + } + + if ((errno == ERANGE) && (parent_pid_check == LONG_MIN)) { + /* Underflow, handle gracefully. */ + parent_pid_check = 1; + } + + if (*end) { + /* Conversion error (for inputs like "X", end will point to X.) */ + parent_pid_check = 1; + } + + if (parent_pid != parent_pid_check) { + nxinfo_good << "Parent PID verification via first argument failed, trusting getppid ()." << std::endl; + } + + killing_process_work (parent_pid); +} + +int main (int argc, char **argv) { + if (argc > 1) { + killing_process_init (argc, argv); + } + else { + /* That's the main process. */ + + /* First, fork and create the "killing process". */ + pid_t pid = fork (); + + if (0 == pid) { + /* Child process. */ + pid_t parent_pid = getppid (); + + /* Prepare to pass-through parent PID. */ + std::stringstream ss; + ss << parent_pid; + + std::vector new_argv; + new_argv.push_back (std::string (argv[0])); + new_argv.push_back (ss.str ()); + + std::vector new_argv_c_str; + for (std::vector::iterator it = new_argv.begin (); it != new_argv.end (); ++it) { + const char *elem = (*it).c_str (); + new_argv_c_str.push_back (strndup (elem, std::strlen (elem))); + } + + /* Add null pointer as last element. */ + new_argv_c_str.push_back (0); + + /* Relaunch, with argv[1] containing the ppid. */ + if (0 != execvp (new_argv_c_str.front (), &(new_argv_c_str.front ()))) { + const int saved_errno = errno; + std::cerr << "Failed to start \"killing process\"! Panic!" << std::endl; + std::cerr << "System error: " << std::strerror (saved_errno) << std::endl; + exit (EXIT_FAILURE); + } + } + else if (0 > pid) { + const int saved_errno = errno; + std::cerr << "Error while forking main process! Panic!" << std::endl; + std::cerr << "System error: " << std::strerror (saved_errno) << std::endl; + exit (EXIT_FAILURE); + } + else { + /* Main process. */ + /* Falls through to general code below. */ + } + } + + setup_faulty_logger (); + + pthread_t thread_id = spawn_thread (); + + setup_good_logger (); + + install_signal_handler (); + + /* print_sigmask (); */ + + log_task (NULL); + + pthread_join (thread_id, NULL); + + exit (EXIT_SUCCESS); +} -- cgit v1.2.3