#include "Watchdog.h" #include "watchdogConf.h" #include #include #include #include #include #include #include #include #include #include WatchdogTask::WatchdogTask (): fd(0) { } WatchdogTask::~WatchdogTask() { } int WatchdogTask::performOperation() { int result = 0; // Only create the FIFO if it does not exist yet if(not std::filesystem::exists(watchdog::FIFO_NAME)) { // Permission 666 or rw-rw-rw- mode_t mode = DEFFILEMODE; result = mkfifo(watchdog::FIFO_NAME.c_str(), mode); if(result != 0) { std::cerr << "eive-watchdog: Could not created named pipe at " << watchdog::FIFO_NAME << ", error " << errno << ": " << strerror(errno) << std::endl; return -2; } #if WATCHDOG_VERBOSE_LEVEL >= 1 std::cout << "eive-watchdog: Pipe at " << watchdog::FIFO_NAME << " created successfully" << std::endl; #endif } // Open FIFO read only and non-blocking fd = open(watchdog::FIFO_NAME.c_str(), O_RDONLY | O_NONBLOCK); if(fd < 0) { std::cerr << "eive-watchdog: Opening pipe " << watchdog::FIFO_NAME << "read-only failed with " << errno << ": " << strerror(errno) << std::endl; } while(true) { WatchdogTask::LoopResult loopResult = watchdogLoop(); switch(loopResult) { case(LoopResult::OK): { break; } case(LoopResult::CANCEL_RQ): { if(state == States::RUNNING) { state = States::SUSPENDED; } break; } case(LoopResult::TIMEOUT): { std::cout << "eive-watchdog: The FIFO timed out!" << std::endl; break; } case(LoopResult::RESTART_RQ): { if(state == States::SUSPENDED) { state = States::RUNNING; } break; } } } if (close(fd) < 0) { std::cerr << "eive-watchdog: Closing named pipe at " << watchdog::FIFO_NAME << "failed, error " << errno << ": " << strerror(errno) << std::endl; } std::cout << "eive-watchdog: Finished" << std::endl; return 0; } WatchdogTask::LoopResult WatchdogTask::watchdogLoop() { using namespace std::chrono_literals; char readChar; struct pollfd waiter = {}; waiter.fd = fd; waiter.events = POLLIN; switch(state) { case(States::SUSPENDED): { // Sleep, then check whether a restart request was received std::this_thread::sleep_for(1000ms); break; } case(States::RUNNING): { // Continue as usual break; } case(States::NOT_STARTED): { // This should not happen std::cerr << "eive-watchdog: State is NOT_STARTED, configuration error" << std::endl; break; } case(States::FAULTY): { // TODO: Not sure what to do yet. Continue for now break; } } // 10 seconds timeout, only poll one file descriptor switch(poll(&waiter, 1, watchdog::TIMEOUT_MS)) { case(0): { return LoopResult::TIMEOUT; } case(1): { if (waiter.revents & POLLIN) { ssize_t readLen = read(fd, buf.data(), buf.size()); if (readLen < 0) { std::cerr << "eive-watchdog: Read error on pipe " << watchdog::FIFO_NAME << ", error " << errno << ": " << strerror(errno) << std::endl; break; } for(ssize_t idx = 0; idx < readLen; idx++) { readChar = buf[idx]; // Cancel request if(readChar == 'c') { return LoopResult::CANCEL_RQ; } // Begin request. Does not work if the operation was not suspended before else if(readChar == 'b') { return LoopResult::RESTART_RQ; } // Everything else: All working as expected else { } } #if WATCHDOG_VERBOSE_LEVEL == 2 std::cout << "Read " << readLen << " byte(s) on the pipe " << FIFO_NAME << std::endl; #endif } else if(waiter.revents & POLLERR) { std::cerr << "eive-watchdog: Poll error error on pipe " << watchdog::FIFO_NAME << std::endl; } else if (waiter.revents & POLLHUP) { // Writer closed its end } break; } default: { std::cerr << "eive-watchdog: Unknown poll error at " << watchdog::FIFO_NAME << ", error " << errno << ": " << strerror(errno) << std::endl; break; } } return LoopResult::OK; }