// \file service.hpp // // Copyright (C) 2014 MicroNeil Research Corporation. // // This program is part of the MicroNeil Research Open Library Project. For // more information go to http://www.microneil.com/OpenLibrary/index.html // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, write to the Free Software Foundation, Inc., 59 Temple // Place, Suite 330, Boston, MA 02111-1307 USA //============================================================================== /* \brief The service module provides a framework for implementing *nix daemons and Windows services. */ #ifndef SERVICE_HPP #define SERVICE_HPP #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) #ifndef WIN32 #define WIN32 #endif #endif #ifdef WIN32 #include #else #include #endif #include #include #include #ifdef WIN32 int main(int argc, char *argv[]); VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv); VOID WINAPI ServiceCtrlHandler(DWORD message); #else int main(int argc, char *argv[]); #endif namespace CodeDweller { /** Singleton class that implements a daemon (*nix) or service (Windows). This class implements a *nix daemon or a Windows service. To implement a daemon or service, implement the required methods of this class, and link with service.cpp. When compiled under *nix, the file service.cpp contains the definition of main for the *nix daemon. When compiled under Windows, the file service.cpp contains the entry points for the Windows service. Nomenclature:
  1. Service is a *nix daemon or Windows service.
  2. Message is a posix signal or Windows message. This class supports the following messages:
    1. Pause. This is the posix TSTP signal or Windows Pause message. This instructs the service to temporarily stop running.
    2. Resume. This is the posix CONT signal or Windows Resume message. This instructs the service to resume running after receiving a Pause message. If the service isn't temporarily stopped after receiving a Pause message, the Resume message has no effect.
    3. Stop. This is the posix TERM signal or Windows Stop or Shutdown message. This instructs the service to shut down and exit.
  3. Callback. This is a function that is executed when a message is received.
*/ class Service { public: /// Callback functor interface. class Callback { public: /// Callback method. virtual void operator()() = 0; }; /// Register a callback for receipt of Pause. // // \param[in] pauseFunctor is the function object to invoke when // Pause is received. // static void onPauseCall(Callback &pauseFunctor); /// Register a callback for receipt of Resume. // // \param[in] resumeFunctor is the function object to invoke when // Resume is received. // static void onResumeCall(Callback &resumeFunctor); /// Register a callback for receipt of Stop. // // \param[in] stopFunctor is the function object to invoke when // Stop is received. // static void onStopCall(Callback &stopFunctor); /// Check whether Pause was received. // // \returns if the Pause message was received, false otherwise. // static bool receivedPause(); /// Check whether Resume was received. // // \returns if the Resume message was received, false otherwise. // static bool receivedResume(); /// Check whether the last message received was Stop. // // \returns true if Stop was the most recent message received, // false otherwise. // static bool receivedStop(); /// Clear receiving the Pause message. static void clearReceivedPause(); /// Clear receiving the Resume message. static void clearReceivedResume(); /// Clear receiving the Stop message. static void clearReceivedStop(); /// Get a reference to the command-line arguments. // // \returns a reference to the vector of command-line arguments of // the application. Index i corresponds to command-line argument // i. // static const std::vector &arguments(); /// Set the timeout for executing one Stop callback. // // If a Stop callback takes longer than the specified timeout, the // service aborts. // // \param[in] timeout_ms is the timeout in milliseconds. If a // value less than 1 is specified, a value of 1 is used. // static void setStopCallbackTimeout_ms(int timeout_ms); private: /// Private constructor prevents instantiation. Service(); /// Prevent copying. Service(Service const&) {} /// Prevent assignment. void operator=(Service const&) {} /// Get the instance of the singleton. // // \returns a reference to the singleton. // static Service& getInstance(); /// Main entry point. // // \param[in] argc is the number of arguments. // // \param[in] argv is an array of strings containing the // command-line arguments. The end of the array is indicated by a // null pointer. // // \returns exit code of the service. // int main(int argc, char *argv[]); #ifdef WIN32 /// Service entry point for Windows. // \param[in] argc is the number of arguments. // // \param[in] argv is an array of strings containing the // command-line arguments. The end of the array is indicated by a // null pointer. // void serviceMain(DWORD argc, LPTSTR *argv); #endif /// Load the command-line arguments. // // This method loads the object with the command-line parameters. // // \param[in] argc is the number of arguments. // // \param[in] argv is an array of strings containing the // command-line arguments. The end of the array is indicated by a // null pointer. // void loadArguments(int argc, char *argv[]); /// Initialize and run the application. // // \returns the exit status of the service. // int run(); /// Mutex to serialize access to the object. static std::mutex objectMutex; #ifdef WIN32 /// Process a control message. // // \param[in] message is the message to process. // void processCtrlMessage(DWORD message); #else /// Thread start function to receive and process messages. void processMessages(); #endif /// Thread start function for the watchdog thread. // // This thread sleeps until timeoutTime, and then causes the // process to exit. void watchdog(); /// Command-line arguments. static std::vector cmdLineArgs; /// True if Pause message was received. static bool pauseReceived; /// True if Resume message was received. static bool resumeReceived; /// True if Stop message was received. static bool stopReceived; /// Functions to invoke when the Pause is received. static std::vector pauseCallbacks; /// Functions to invoke when the Resume is received. static std::vector resumeCallbacks; /// Functions to invoke when the Stop is received. static std::vector stopCallbacks; /// Stop message callback timeout. static int stopCallbackTimeout_ms; /// Absolute time at which the Stop callback timeout expires. std::chrono::time_point timeoutTime; /// True if the Stop callbacks are being invoked. bool stopCallbacksActive; #ifdef WIN32 /// Status of the service. SERVICE_STATUS serviceStatus; /// Handle for accessing service status on the OS. SERVICE_STATUS_HANDLE serviceStatusHandle = NULL; friend int ::main(int argc, char *argv[]); friend VOID WINAPI ::ServiceMain(DWORD argc, LPTSTR *argv); friend VOID WINAPI ::ServiceCtrlHandler(DWORD message); #else /// Set of signals to wait for. sigset_t signalSet; friend int ::main(int argc, char *argv[]); #endif }; } #endif // SERVICE_HPP